본문 바로가기

복습/C++

[C++] 복습일지 part 1

이것이 저의 첫 글이 되네요

프로그래밍 공부에 발을 들이면서, 개발일지를 쓰면 나중에 도움도되고

일기장 같은 느낌이라 좋을 것 같아서 시작합니다


코딩을 시작한지 얼마 되지 않아서 표현이 미숙 할 수 있어요 ㅎㅎ


18.01.06 [ 복습일지 ]


#1  절차지향프로그래밍과 객체지향프로그래밍

#2  클래스란 무엇인가?

#3  접근제어자

#4  생성자 소멸자 

#5 그 외에 알게 된 것


[ #1 ]

절차지향프로그래밍이란?


- 사실 절차지향과 객체지향을 정반대로 생각하는것이 잘못된 생각인것 같습니다. 

절차지향프로그래밍은 뭐 위에서 아래로 흐르고~~ 그럼 객체지향프로그래밍은 위에서 아래로 흐르지 않는걸까요? 객체지향프로그래밍도 위에서 아래로 흐르게 되어있습니다. 여기서 차이점을 알아야합니다.

절차지향프로그래밍은 프로그램을 순서와 흐름을 설계한뒤 필요한 함수들, 변수들을 설계하는것입니다. 


객체지향프로그래밍이란?


- 객제지향프로그래밍은 사람이 생각하는 '객체' 들을 만든 뒤에 프로그램의 순서와 흐름을 짜는것입니다. 여기서 '객체' 가 무엇인지 한번 알아보겠습니다.

객체는 무엇이든 될 수 있습니다.

'자동차'에는 바퀴, 핸들, 의자 등등이있습니다. 기존의 절차지향프로그래밍에서는 모든 흐름을 설계한뒤에 흐름에 맞추어 바퀴는 이렇게, 그바퀴에 맞춰서 핸들은 이렇게 등등 전체적으로 유기적인 짜임이있습니다. 하지만 객체지향에서프로그래밍에서는 바퀴, 핸들, 의자를 각각의 객체로 보고, 의자의 색깔을 바꾸고싶다면, 의자객체의 색깔부분만 바꾸면됩니다. 절차지향에서는 그에맞춰서 다시 짜야겠죠. 여기서 객체지향의 가장  큰 특징 세가지가 나옵니다.


1. 캡슐화 : 캡슐화란 관련된 데이터들을 하나로 묶는것입니다. 또한 캡슐안에있는 가루들처럼, 외부에 보여주고싶지않은 데이터는 감출 수 있습니다.

2. 상속 : 이미 작성된 클래스를 물려받아 새로운 클래스를 작성하는 방법입니다. 재활용성이 용이합니다.

3. 다형성 : 하나의 이름으로 여러가지 상황에 대처를 할 수 있습니다. 예를들어 어떤 가게에는 현금만 받고 어떤가게에는 카드만 받는다고하면, 그 가게이름을 일일이 기억하고 있어야 가지고있는 결제수단에 맞춰 가지만, 다른 한 가게에는 현금, 카드 둘다 된다면, 그 가게 이름 하나만 외우면 된다는것입니다. 여러상황에 대처를 한것이죠.



[ #2 ]

클래스(class) 란 무엇인가?


-일단 객체(instance)와 클래스는 서로 다른개념입니다. 뭐 어느책에서나 붕어빵틀과 붕어빵을 예로 들듯이, class 는 붕어빵틀, 즉 설계도라고 할 수 있고 객체는 붕어빵틀에서 나온 붕어빵, 즉 실체라고 볼 수 있습니다.


클래스는 '필드' 와 '메서드'로 구성이되는데요, '필드(field)'는 만들어진 객체의 상태, '메서드(method)'는 객체의 행동이며, 

'필드(field)'는 클래스에 포함된 '변수(variable)'

'메서드(method)'는 어떻게어떻게 해라, 라는 행동의 집합입니다


자동차 클래스를 작성했다고 예를 들자면, 사실 자동차는 만들어지지않았습니다. 왜냐하면, 설계도를 작성한것이지 자동차를 공장에서 찍어내진 않아서입니다.

그렇다면 클래스를 어떻게 이용하는가? 

C++ 기준에서 말씀드리겠습니다.

Car라는 class가 있다면


class Car{

public:

Car(){

wheel = 4;

color = "blue";

std::cout << " car생성 " << std::endl;

}

void move(){

std::cout << " 움직인다" << std::endl;

}

private:

int wheel;

string color;

};


Car *c = new Car();


가 됩니다. 여기서 Car class의 생성자는 접근제어자가 public이라는 전제조건입니다.

그렇다면  c 라는 것이 객체, 즉 자동차가 Car class의 설계도에 따라 만들어진 것입니다. 


이 자동차는 wheel이 4개이며, 색깔(color)은 blue인 자동차입니다. 또한 move()메서드를 통해 움직일수 있습니다.

다음은 접근제어자입니다.


[ #3 ]

접근제어자란?


public

protected

private



단어의 뜻으로 유추할 수 있는데요

public을 사용하면 어디에서나 사용가능합니다

protected는 같은 클래스, 상속된 자식클래스 안에서 사용가능합니다.

private는 같은 클래스에서만 사용이 가능합니다. 


그럼 public이 아닌 다른 접근제어자들은 다른클래스에서 사용하려면 어떻게 해야하나? 라는 의문점이 드는데요

예를들면, 어린아이가 돈이필요한데 필요하다고해서 아빠지갑에 있는 돈을 마음대로 가져가면 안됩니다.

그래서 아빠에게 필요하다고 말을한 후에 아빠가 줘야합니다. ㅎㅎ...


class Dad{

public:

Dad(){

money = 1000;

}

int giveMoney(){

return money;

}

private:

int money;

};


class Son{

public:

Son(){

money = 0;

}

public:

int money;

};


Dad *d = new Dad();

Son *s = new Son();

이 있을때 


여기에서 

s->money = d->money;


를 가져가려하면 에러가 뜹니다.

그래서 생성한 메서드(method)가 바로 giveMoney() 입니다. 

고쳐쓰면


s->money = d->giveMoney();


giveMoney()는 public 이기때문에 다른 클래스에서 호출이 가능합니다.

giveMoney()메서드를 통해서 Dad클래스의 private인 money를 가져오게 된것이죠.


그럼 왜 쓰는걸까요? 항상 왜가 중요한것같습니다. 


클래스 내부에 있는 데이터를 보호하기 위해 씁니다.

함부로 값이 변경되면 안되겠죠?


C++에서는 접근 제어자를 직접 기술하지않으면, 기본값인 private로 만들어집니다.

java에서는 기본 접근제어자가 패키지 내에서만 가능하도록 되어있습니다. 그래서


[java]

class Car(){ 

Car(){

System.out.println("new Car");

}

}


Car c = new Car();  //main에 있다는가정


를 하게되면 에러가 없습니다.


[c++]

class Car(){ 

Car(){

std::cout << "new Car" << std::endl;

}

};


Car* c = new Car(); //main에 있다는가정, 컴파일 에러


이유는 무엇일까요? 

바로 접근제어자때문입니다 C++은 기본 접근제어자가 private이기때문에 main()함수(외부) 에서 접근하려하면

접근을 할 수 없습니다.


고쳐쓴다면


class Car(){ 

public:

Car(){

std::cout << "new Car" << std::endl;

}

};


이 되어야겠죠.

또한 선언방식에 따라 차이가있는데요


Car c();

Car *d = new Car();


c는 stack메모리에 쌓이게되고, d는 heap메모리에 쌓이게 됩니다.

이게 뭔말이냐 하면, 

d는 포인터이고 c는 논포인터입니다.


d는 heap메모리에 올라가서 delete주기나 메모리조절을 마음대로 할 수 있고

c는 stack메모리에 올라가서 코드블럭이 끝나거나 컴파일이 끝나야 delete가 되며, 메모리조절을 할 수 없습니다.






calculator 클래스가있고

소멸자는 delete를 출력합니다.


컴파일 결과는 다음과 같습니다.


calculator a(4, 6) 을 통해 4,6 설정

a.add() 를 통해 10출력


calculator *c = new calculator(4, 6); 을 통해 4,6 설정

c->add()를 통해 10 출력


delete c; 를 통해 delete출력

calculator * cc = new calculator(1, 2, 3); 을통해 1, 2, 3 설정

cc->add2(); 를 통해 6 출력

delete cc; 를 통해 delete 출력


하고 끝나면 delete는 두번출력되야하는데 마지막에

deleteProgram ended with exit code: 0 에서

delete가 출력이 됩니다.

그이유는 a의 delete인데요

코드블럭이 끝난 이후에야 a는 delete가 됩니다 . stack메모리에 올라간것이죠.


delete a가 가능할까요?


답은 No입니다. 마음대로 메모리 조절을 할 수 없습니다.


또한 하나 차이가있다면

접근방식입니다.

a.add();

c->add();

점과 화살표의 차이입니다.



[ #4 ] 생성자, 소멸자


생성자 : 객체가 생성될때 자동으로 호출되는 함수, return 없음.

클래스이름 (){


}

로 사용한다.

그렇다면 왜 사용할까?


바로, 객체를 생성할 때 생성과동시에 초기화를 해주기 위함이다. 생성자도 함수와같이 인자를 받을 수 있으며, 오버로딩이 가능하다.


소멸자 : 객체가 파괴될때 호출되는 함수이다,  반환형식(void)를 설정할 수 없으며, return도 없습니다. 인자를 받아들이지도 않습니다.


new 연산자를 사용하여 할당된 개체는

delete 연산자를 통하여  명시적으로 할당이 해제됩니다.


java와 달리 c++에서는 garbage collector가 없어서 delete를 통해 메모리관리를 해줘야합니다. 아직은 그정도가 아니라서 알고있으려고합니다 


[ #5 ] 그 외에 알게 된 것들


switch(){

case 1:

break;

case 2:

break;

}


이렇게 스위치문 내부의 case 1: 안에 내용이 여러줄이 있다면 코드블럭으로 감싸줘야한다는점을 알았습니다

switch(){

case 1:{


break;

}

case 2:{


break;

}

}


또한 생성자를 명시적으로 선언 해주지않았다면 컴파일시 자동으로 기본생성자가 생성된다.

Car car;   // 디폴트 생성자를 암시적 호출

Car car = Car(); // 디폴트 생성자를 명시적으로 호출

Car *c = new Car; // 디폴트 생성자를 암시적으로 호출


하지만 생성자가 하나라도 있을 경우에 기본생성자를 만들어주지않는다.

class Car(){

public:

Car(int tempWheel, string tempColor){

wheel = wheel;

color = tempColor;

}

private:

int wheel;

string color;

}


Car 클래스가 있지만 생성자에 인자가있다. 그렇다면 기본생성자를 추가해주지않아서

Car car = Car(); 를하면 컴파일 에러가 난다.

왜냐하면 

Car(int tempWheel, string tempColor){ ... }

라는 생성자가있기 때문에 하나가 있는것이다 

그래서 기본생성자를 만들어주지않는다


해결법은 만들어주면된다

class Car(){

public:

Car(int tempWheel, string tempColor){

wheel = wheel;

color = tempColor;

}

Car(){

}

private:

int wheel;

string color;

}

이렇게 해준다면 컴파일 에러가 나지 않는다.







처음쓰는건데 틀린부분도 있을게 분명합니다. 지적해주시면 감사하겠습니다.