C++ Chapter 04. 클래스의 완성. 04-3 생성자(Constructor)와 소멸자(Destructor)
C++ Chapter 04. 클래스의 완성.
04-3 생성자(Constructor)와 소멸자(Destructor)
* 생성자의 이해
// 생성자는 객체 생성과 동시에 초기화 할 수 있다.
// 클래스의 이름과 함수의 이름이 동일하다.
// 반환형이 선언되어 있지 않으며, 실제로 반환하지 않는다
// 생성자도 함수의 일종이니 오버로딩이 가능하다
// 생성자도 함수의 일종이니 매개변수에 '디폴트 값'을 설정 할 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | #include <iostream> using namespace std; class SimpleClass { int num1; int num2; public: SimpleClass() { num1=0; num2=0; } SimpleClass(int n) // n { num1=n; num2=0; } SimpleClass(int n1, int n2) // 100, 200 { num1=n1; num2=n2; } /* SimpleClass(int n1=0, int n2=0) { num1=n1; num2=n2; } */ void ShowData() const { cout<<num1<<' '<<num2<<endl; } }; int main(void) { SimpleClass sc1; sc1.ShowData(); SimpleClass sc2(100); sc2.ShowData(); SimpleClass sc3(100, 200); sc3.ShowData(); return 0; } | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | #include <iostream> using namespace std; class SimpleClass { int num1; int num2; public: SimpleClass(int n1=0, int n2=0) { num1=n1; num2=n2; } void ShowData() const { cout<<num1<<' '<<num2<<endl; } }; int main(void) { SimpleClass sc1(); // 함수의 원형 선언! (29행에 정의되어 있는 함수를 호출하기 위해) SimpleClass mysc=sc1(); mysc.ShowData(); return 0; } SimpleClass sc1() { SimpleClass sc(20, 30); return sc; } | cs |
* Point, Rectangle 클래스에 생성자 적용
* '멤버 이니셜라이저(Member Initializer)'를 이용한 멤버 초기화
* 객체의 생성과정
// 이니셜라이저가 선언되지 않았다면, 1단계 : 메모리 공간의 할당, 3단계 : 생성자의 몸체부분의 실행으로 객체생성은 완성된다
// 그러나 생성자는 이니셜라이저처럼 선택적으로 존재하는 대상이 아니다.
// 생성자는 반드시 호출이 된다. 우리가 생성자를 정의하지 않으면, '디폴트 생성자(default constructor)'라는 게 자동으로 삽입되어 호출이 된다
* '멤버 이니셜라이저(Member Initializer)'를 이용한 변수 및 const 상수(변수)의 초기화
// '멤버 이니셜라이저'는 객체가 아닌 멤버의 초기화에도 사용할 수 있다.
// 1. 프로그래머는 생성자의 몸체에서 초기화 하는 방법,
// 2. 이니셜라이저를 이용하는 초기화 방법 중에서 선택이 가능하다
// 일반적으로 멤버변수의 초기화에 있어서는 2. 이니셜라이저를 선호하는 편이다. 두 가지 이점이 있기 때문이다.
1. 초기화의 대상을 명확히 인식할 수 있다. 2. 성능에 약간의 이점이 있다.
// const 멤버변수도 이니셜라이저를 이용하면 초기화가 가능하다!
* 이니셜라이저의 이러한 특징은 멤버변수로 참조자를 선언할 수 있게 합니다
// const 변수와 마찬가지로 '참조자'도 선언과 동시에 초기화가 이뤄져야 한다.
// 따라서 이니셜라이저를 이용하면 참조자도 멤버변수로 선언될 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | #include <iostream> using namespace std; class AAA { public: AAA() { cout<<"empty object"<<endl; } void ShowYourName() { cout<<"I'm class AAA"<<endl; } }; class BBB { private: AAA &ref; const int # public: BBB(AAA &r, const int &n) : ref(r), num(n) { } void ShowYourName() { ref.ShowYourName(); cout<<"and"<<endl; cout<<"I ref num "<<num<<endl; } }; int main(void) { AAA obj1; BBB obj2(obj1, 20); obj2.ShowYourName(); return 0; } | cs |
* 디폴트 생성자(Default Constructor)
// 매개변수가 void형으로 선언된 디폴트 생성자는, 생성자가 하나도 정의되어 있지 않을 때에만 삽입이 된다.
// 메모리 공간의 할당 이후에 생성자의 호출까지 완료되어야 '객체'라 할 수 있다.
// 즉, 객체가 되기 위해서는 반드시 하나의 생성자가 호출되어야 한다
AAA * ptr = new AAA; // 이런 형태로 생성해도 객체의 생성과정에서 생성자가 호출된다
AAA * ptr = (AAA*)malloc(sizeof(AAA)); // malloc 함수를 대신 이용하면 생성자는 호출되지 않는다
// 실제로는 AAA 클래스의 크기정보만 바이트 단위로 전달되기 때문에 생성자가 호출될 리 없다.
// 따라서 객체를 동적으로 할당하려는 경우에는 반드시 new 연산자를 이용해야 한다
* 생성자 불일치
* private 생성자
// 객체의 생성이 클래스의 외부에서 진행되면, 생성자는 public으로 선언되어야 한다
// 객체의 생성이 클래스의 내부에서 진행되면, 생성자는 private으로 선언되어야 한다
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | #include <iostream> using namespace std; class AAA { private: int num; public: AAA() : num(0) {} AAA& CreateInitObj(int n) const { AAA * ptr=new AAA(n); // 클래스 내부에서는 private 생성자의 호출이 가능하다 return *ptr; } void ShowNum() const { cout<<num<<endl; } private: AAA(int n) : num(n) {} // 생성자가 private이므로 클래스 외부에서는 이 생성자의 호출을 통해서 객체 생성이 불가능하다 }; int main(void) { AAA base; base.ShowNum(); AAA &obj1=base.CreateInitObj(3); obj1.ShowNum(); AAA &obj2=base.CreateInitObj(12); obj2.ShowNum(); delete &obj1; delete &obj2; return 0; } | cs |
* 소멸자의 이해와 활용
// 객체생성시 반드시 호출되는 것이 생성자라면,
// 객체소멸시 반드시 호출되는 것은 소멸자이다.
1. 반환형이 선언되어 있지 않으며, 실제로 반환하지 않는다
2. 매개변수는 void형으로 선언되어야 하기 때문에 오버로딩도, 디폴트 값 설정도 불가능하다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | #include <iostream> #include <cstring> using namespace std; class Person { private: char * name; int age; public: Person(char * myname, int myage) {// 불필요한 메모리 공간의 낭비 또는 부족을 막기위해서 문자열의 길이만큼 메모리 공간을 동적 할당하고 있다 int len=strlen(myname)+1; name=new char[len]; strcpy(name, myname); age=myage; } void ShowPersonInfo() const { cout<<"이름: "<<name<<endl; cout<<"나이: "<<age<<endl; } ~Person() { delete []name; cout<<"called destructor!"<<endl; } }; int main(void) { Person man1("Lee dong woo", 29); Person man2("Jang dong gun", 41); man1.ShowPersonInfo(); man2.ShowPersonInfo(); return 0; } | cs |