[열혈 C++] 생성자와 소멸자
생성자
생성자란 반환값이 없고 클래스와 이름이 같은 멤버함수로 클래스 객체가 생성될 때 한 번만 호출되는 함수입니다. 생성자도 함수이므로 오버로딩이 가능하고 디폴트 값을 설정할 수 있습니다. 그럼 간단한 생성자 예제를 작성해 보겠습니다.
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class A {
private:
int num1;
public:
A(int num) { //생성자 정의
num1 = num;
}
void ShowNum() {
cout << num1 << endl;
}
};
int main(void) {
A clsA(30); //30을 생성자에 인자로 전달하며 클래스 생성
A* clsA2 = new A(50); //50을 생성자에 인자로 전달하며 동적할당으로 클래스 생성
clsA.ShowNum();
clsA2->ShowNum();
delete clsA2;
return 0;
}
30 50 |
디폴트 생성자
모든 객체는 만들어질 때 하나의 생성자가 호출되어야 합니다. 그래서 우리가 명시적으로 생성자를 정의하지 않는다면 컴파일러에 의해 디폴트 생성자가 자동으로 삽입됩니다. 디폴트 생성자는 "클래스이름 (){}"의 형태로 인자와 내용이 없는 형태를 띠고 있습니다. 하지만 우리가 위 코드처럼 생성자를 정의해 주게 되면 디폴트 생성자는 삽입되지 않습니다. 그래서 평소처럼 인자를 전달하지 않고 클래스를 생성하게 되면 오류가 발생합니다. 이를 막기 위해 생성자 오버로딩을 사용합니다.
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class A {
private:
int num1;
public:
A(int num) {
num1 = num;
}
A() {} //생성자 오버로딩
void ShowNum() {
cout << num1 << endl;
}
};
int main(void) {
A clsA(30);
A* clsA2 = new A(50);
A clsA3; //생성자 오버로딩을 해서 오류가 발생하지 않음
clsA.ShowNum();
clsA2->ShowNum();
delete clsA2;
return 0;
}
30 50 |
이니셜라이저
이니셜라이저란 클래스의 생성자가 호출될 때 멤버변수나 멤버객체들을 초기화 해주는 장치입니다. 생성자이름(인자) : 이니셜라이저 {생성자내용}의 형태로 사용합니다. 인자를 받으면 num1에 저장하고 인자를 받지 않으면 num1에 0을 저장하는 간단한 이니셜라이저의 예를 들어보겠습니다.
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;
class A {
private:
int num1;
public:
A(int num) :num1(num) {
}
A() : num1(0) {}
void ShowNum() {
cout << num1 << endl;
}
};
int main(void) {
A clsA(30);
A* clsA2 = new A(50);
A clsA3;
clsA.ShowNum();
clsA2->ShowNum();
clsA3.ShowNum();
delete clsA2;
return 0;
}
30 50 0 |
초기화대상(초기화값) 의 형태로 이니셜라이저를 작성합니다. 이니셜라이저로 초기화하는 방식은 생성자 내부에 써서 초기화하는 방식에 비하여 두 가지 장점이 있습니다. 초기화의 대상을 명확히 인식할 수 있다는 점과 성능이 약간 향상된다는 점입니다. 이니셜라이저를 사용하면 변수의 선언과 동시에 초기화가 되어 "int num1 = num;"의 형태가 됩니다. 하지만 내부에 쓰게 되면 "int num1; num1=num;"의 형태로 두줄에 걸쳐 쓰는 것이 되기 때문에 이니셜라이저를 사용하면 약간의 성능향상이 이루어지는 것입니다.
소멸자
소멸자란 생성자와 반대되는 개념의 함수로 객체가 소멸될때 한번 호출되는 함수입니다. ~클래스이름(){소멸자내용}의 형태로 작성합니다. 주로 생성자 내에서 new를 이용한 동적할당을 했을 때 delete로 해제하기 위해서 사용합니다. 동적할당을 해제하는 간단한 소멸자의 예를 들어보겠습니다.
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
using namespace std;
class Person {
private:
char* name;
int age;
public:
Person(const char* NAME, int AGE) : age(AGE) { //생성자
name = new char[strlen(NAME) + 1];
strcpy(name, NAME);
cout << "생성자 호출" << endl;
}
void ShowPersonInfo() {
cout << "이름: " << name << endl;
cout << "나이: " << age << endl;
}
~Person() { //소멸자
delete[]name;
cout << "소멸자 호출" << endl;
}
};
int main(void) {
Person man("신용준", 23);
man.ShowPersonInfo();
return 0;
}
생성자 호출 이름: 신용준 나이: 23 소멸자 호출 |
소멸자를 사용하면 프로그래머의 실수로 메모리 누수가 발생하는것을 방지할 수 있습니다.
마치며
오늘은 생성자와 소멸자 그리고 이니셜라이저를 공부해 보았습니다. 제가 든 예시들은 간단한 예시들이지만 활용만 잘한다면 클래스를 만들어 나가는 데에 매우 유용한 도구가 될 것입니다.