오늘은 클래스에서 생성자와 소멸자에 대해 알아보도록 하죠. 생성자는 클래스 객체 변수를 선언할 때 호출 되는 함수이고 소멸자는 클래스 객체 변수가 소멸 할 때 호출 되는 함수입니다. 함수명은 클래스명과 동일한 이름으로 되어 있는데 예로 AAA라는 클래스에 AAA()함수이면 생성자 함수이고 같은이름인데 '~' 기호가 붙어 ~AAA()이면 소멸자 함수입니다. 이걸 왜 사용하냐면 처음 객체변수를 선언할 때 메모리 할당이나 클래스 작업을 수행하기전 초기화 작업을 수행하는 명령어들을 이곳에서 표현하면 좋고요. 소멸자 함수는 마지막 메모리 해제와 같은 마무리 작업을 수행하는 코딩을 표현하면 좋습니다. 이제 생성자와 소멸자 함수를 알아보도록 하죠.
생성자 함수와 소멸자 함수는 다음과 같은 구조로 되어 있습니다.
class 클래스명{
접근지정자:
자료형1 변수1;
자료형2 변수2; //멤버변수
접근지정자:
클래스명(){} //생성자 함수
~클래스명(){} //소멸자 함수
}
이렇게 클래스명과 동일합니다. 예를 들어 살펴볼까요.
class AAA{
public:
int a=10;
public:
AAA(){ cout<<"생성자"<<endl;}
~AAA(){ cout<<"소멸자"<<endl;}
void output(){
cout<<a<<" 입니다."<<endl;
}
};
이렇게 클래스가 선언 되었다고 합시다.
class AAA op1;
라고 선언하면 아래 생성자 함수가 호출 됩니다.
AAA(){
cout<<"생성자"<<endl;
}
이것은 생성자 함수로 클래스 변수가 선언되면 이 함수가 자동으로 호출 됩니다. 참고로 인자가 없는 생성자 함수는 디폴트로 기본 생성됩니다. 생성자 함수는 여러개를 만들 수 있습니다. 클래스 변수가 어떤 특정한 값을 갖는 객체 변수를 선언 할 수 있고 그냥 객체 변수를 선언 할 수 있는데 다음과 같은 표현이 가능합니다.
AAA(int input){
a=input;
}
이 겨우는 다음과 같은 객체 변수 선언일 때 생성자 함수가 호출 됩니다.
class AAA op2(30);
그러면 결과를 확인해 볼까요.
#include
using namespace std;
class AAA{
public:
int a=10;
public:
AAA(){ cout<<"생성자"<<endl;}
AAA(int input){ a=input;}
~AAA(){ cout<<"소멸자"<<endl;}
void output(){
cout<<a<<" 입니다."<<endl;
}
};
int main(int argc, char** argv) {
class AAA op1;
class AAA op2(30);
op1.output();
op2.output();
return 0;
}
[결과]
결과를 잘 보시면 객체 변수 op1, po2가 선언되면 생성자 함수 두개가 호출 됩니다. 출력에서는 생성자 글자가 한번 출력 되는데 그 이유는 AAA()함수와 AAA(int input)함수가 호출 되었다는 의미입니다. output()함수의 결과가 두번 호출이 되는데 각각 a의 값이 출력 되는데 op1의 a값은 수정이 안되어 있어서 초기값 10이 출력이 되고 op2는 생성자 함수에서 30으로 수정 되었기 때문에 30이 출력 되었습니다. 그리고 프로그램이 종료 됨으로 소멸자 함수가 두번 호출 되니깐 소멸자 글자가 두번 나왔습니다.
다시 정리를 하면,
class AAA op1;
이때 생성자 AAA()함수가 호출 됩니다.
op1.output();
클래스 멤버함수를 호출하여 그 결과를 출력 합니다
프로그램이 종료 전에 소멸자 ~AAA()함수가 호출 됩니다.
어떤 느낌인지 아시겠지요.
그냥 생성자와 소멸자 함수가 호출된다 정도로 하고 넘어가면 안되겠죠. 왜! 쓰는지에 대해 적절할 예제를 통해 알아 봐야겠죠.
[전체소스]
#include
using namespace std;
class AAA{
public:
char *arr_p;
public:
AAA(){ arr_p = new char [10];}
AAA(int size){ arr_p = new char [size];}
~AAA(){ delete[] arr_p; arr_p=NULL;}
void output(){
cout<<arr_p<<endl;
}
};
int main(int argc, char** argv) {
class AAA op1;
cin>>op1.arr_p;
op1.output();
return 0;
}
위 코딩을 보면,
char *arr_p;
포인트 변수를 선언 하였습니다. 참고로 메모리 할당을 하지 않은 상태로 크기가 결정되지 않았습니다.
AAA(){ arr_p = new char [10];}
AAA(int size){ arr_p = new char [size];}
두개의 생성자 함수로 그냥 객체변수를 선언하면 크기를 10으로 했고 객체변수를 선언 할 때 size를 지정해 주면 그 크기로 문자열포인트 변수의 크기를 지정하게 됩니다.
크기가 지정 된 상태에서 cin(입력)으로 콘솔창에서 문자열을 입력 받아 포인트 변수에 저장하게 됩니다.
cin>>op1.arr_p;
그리고 나서 그 결과를 출력합니다.
op1.output();
마지막으로 프로그램 종료 전 이 클래스는 소멸자 함수를 호출하여 할당 된 포인트 변수 해제합니다.
~AAA(){ delete[] arr_p; arr_p=NULL;}
이렇게 프로그램은 돌아 갑니다. 결과가 어떻게 출력 되는지 볼까요.
[결과]
프로그램이 종료 되면은 자동으로 할당 된 것들이 해제 되는데 구지 소멸자 함수에서 코딩 할 필요가 있으냐하고 생각 될 수 있을 거에요. 여 코딩에서는 물론 그 질문이 맞을 수 있습니다. 프로그램이 종료 됨으로 자동으로 할당 된 것들이 해제 됩니다. 해제 되기 전에 소멸자 함수가 호출 하여 포인터 변수를 해제 시키는 동작입니다.
원리를 이해하는 차원으로 이렇게 표현 한 것일 뿐이고요. 나중에 클래스도 포인터 객체 변수로 선언하여 할당과 해제를 중간에 할 수 있습니다. 즉, 이말은 프로그램 중간에 클래스 객체 변수가 선언되고 해제 됨으로 프로그램은 종료 되지 않는 상태가 되는데 이때 클래스 안에 변수들을 할당과 해제를 시켜주면 메모리 할당 관리를 효율적으로 할 수 있습니다. 그리고, 꼭 이런 용도를 쓰는 것이 아니라 생성자함수는 초기화 작업이 필요한 명령어들을 에서 수행하고 마무리 작업이 필요한 명령어들을 소멸자함수에서 사용한다는 개념만 잘 이해하시면 됩니다.
생성자함수와 소멸자함수를 간단히 살펴보았습니다. 이 생성자와 소멸자를 좀더 이해를 돕기 위해서 상속 클래스의 예를 들어야 하는데 상속 클래스는 아직 안다루었기 때문에 거기까지는 설명하지 않겠습니다. 나중에 상속 클래스에 대해 설명할때 빠진 이부분을 추가로 설명하겠습니다.