생성자와 소멸자
[생성자란?]
생성자란 객체를 즉시 사용할 수 있는 상태로 초기화 시켜주는 클래스의 멤버함수이다.
따라서 생성자를 사용하면 생성된 객체의 상태를 일일이 신경을 써 초기화 하지 않고도 사용 할 수 있다.
단, 생성자가 하는 일이 너무 많으면 오히려 코드에 대한 이해도가 복잡해 질수 있음으로 꼭 필요한 작업만 사용하는 것이 좋다.
- 클래스로 만들어지는 객체를 초기화 해주는 멤버함수이다.
- 클래스로 객체를 선언할 때 자동적으로 호출된다.
- 사용자가 직접 호출해 사용할 수 없다. (함수의 호출이 명시적이지 않다.)
- 이름은 클래스의 이름과 동일하게 작성해야 한다.
- 리턴 값이 void인 함수이여야 하며 void를 생략하여 함수를 선언하고 정의한다. (리턴 값을 가질 수 없음.)
- 객체 생성 때 마다 호출되어 생성된 객체의 멤버변수를 초기화 시킨다.
- 가상함수로 선언 될 수 없다.
생성자 함수의 선언 및 정의 방법
생성자 함수도 멤버 함수임으로 클래스 내에 정의 하면 된다.
또한 다른 멤버함수와 같이 클래스 내부에서는 함수의 선언만 하고 클래스 외부에서 정의하는 것도 가능하다.
1
2
3
4
5
6
7
8
9
|
//클래스 내부에 생성자 함수를 정의 하는 방법
class 클래스명{
:
public:
클래스명() { //생성자 함수의 정의. return type을 쓰지 않는다.
: //이곳에 생성자 함수의 내용을 기재 한다.
}
: //클래스의 다른 내용
};
|
cs |
1
2
3
4
5
6
7
8
9
10
11
|
//클래스 내부에는 생성자 함수에 대한 선언을 하고 클래스 외부에 생성자 함수를 정의 하는 방법
class 클래스명{
:
public:
클래스명() //생성자 함수의 정의. return type을 쓰지 않는다.
:
};
클래스명::클래스명() {
: //이곳에 생성자 함수의 내용을 기재 한다.
}
|
cs |
생성자 함수는 오버로딩이 가능하다.
생성자 함수를 오버로딩 한다면 객체를 선언 할 때 건네준 매개변수 값에 따라 어떠한 생성자 함수가 호출 될지 결정된다.
오버로딩 함수에는 수적 제한이 없으며 매개변수가 없는 생성자 함수를 dafault 생성자 함수라 한다.
1
2
3
4
5
6
7
8
9
|
/* 예제1 */
Point p1; // default 생성자 함수가 호출된다.
Point p2(10, 20); // 매개변수를 받아가는 생성자 함수가 호출된다.
/* 예제2 */
Stud arr[3] = { Stud(), Stud(2,25), Stud(3,35) };
arr[0].prn(); // 번호: 0 나이: 0
arr[1].prn(); // 번호: 2 나이: 25
arr[2].prn(); // 번호: 3 나이: 35
|
cs |
[소멸자란?]
소멸자란 객체의 사용이 끝난 후 객체에 대한 뒤처리 작업 등을 자동으로 수행 할 수 있도록 해주는 class의 멤버함수 이다.
소멸자를 사용하면 생성된 객체에 대한 뒤처리를 신경쓰지 않고 편하게 프로그래밍을 할 수 있다.
단, 생성자와 마찬가지로 소멸자 함수가 하는 작업이 너무 많아지면 프로그램의 이해가 어려워지고 오류 발생 위험이 높아지는 등의 문제가 있음으로
꼭 필요한 내용만 소멸자 함수에 포함시키는게 좋다.
- 클래스로 만들어지는 객체에 대한 뒤처리를 해주는 멤버함수이다. (뒤처리 작업 = 동적메모리할당 해제)
- 사용중인 객체가 소멸되는 시점에 자동으로 호출된다.
- 직접 호출해 사용할 수 없다.
- 클래스의 이름과 동일하게 작성해야 하되, 생성자 함수와 구분하기 위해 함수명 앞쪽에 ~연산자를 붙인다. (~는 틸드(tilde) 또는 bit not으로 읽으면 된다.)
- 리턴 값이 void인 함수여야 하며 void를 생략하여 함수를 선언하고 정의 한다. (리턴 값을 가질 수 없다.)
- 매개변수를 받아올 수 없다. 따라서 소멸자에 대한 오버로딩이 불가함으로 class 하나에 오직 한 개의 소멸자 함수만 존재해야 한다.
- 객체가 소멸될 때 마다 호출되어 소멸된 객체에 대한 뒤처리 작업을 한다. (전역객체는 프로그램 종료 시 한번, 지역객체는 객체 소멸 시마다 실행된다.)
소멸자 함수의 사용방법
소멸자 함수는 객체에 대한 뒤처리를 하기 위해 사용하며 주로 동적 메모리 할당을 자동으로 해제하기 위해 사용한다.
1
2
3
4
5
6
7
8
9
10
|
//클래스 내부에 소멸자 함수를 정의 하는 방법
class 클래스명{
:
public:
:
~클래스명(){ //소멸자 함수의 정의. return type을 쓰지 않는다.
: //이곳에 소멸자 함수의 내용을 기재 한다.
}
: //클래스의 다른 내용
};
|
cs |
[복사생성자란?]
복사생성자란 객체를 만들면서 생성자 함수에 매개변수로 기존에 생성한 객체를 건네줄 경우 컴파일러가 자동으로 생성해주는 생성자 함수이다. 원래 생성자 함수에 어떠한 매개변수를 건네주려면 해당 매개변수를 받아올 수 있는 생성자 함수를 사용자가 직접 만들어야 하지만 객체가 매개변수로 넘어갈 경우에는 사용자가 생성자 함수를 만들지 않아도 컴파일러가 자동으로 복사생성자를 만들어 객체를 매개변수로 받아올 수 있게 해준다.
- 컴파일러에 의해 자동으로 생성되는 생성자 함수이다.
- 복사생성자는 객체를 생성자의 매개변수로 받아갈 수 있게 해준다.
- 필요할 경우 사용자가 직접 복사 생성자를 만들어 사용 할 수도 있다.
복사생성자의 사용방법
사용자가 직접 정의하지 않아도 생성자 함수에 매개변수로 객체를 건네주면 컴파일러가 자동으로 생성한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#include <iostream.h>
class Stud {
private :
int no;
int nai;
public :
Stud(int x, int y) {
no = x, nai = y;
}
void print() {
cout << "번호: "<< no << "\t" << "나이: " << nai << endl;
}
};
void main() {
Stud arr[3] = { Stud(1, 15), Stud(2, 25), Stud( arr[1] ) };
arr[0].print();
arr[1].print();
arr[2].print();
}
|
cs |
//실행결과 번호: 1 나이: 15 번호: 2 나이: 25 번호: 2 나이: 25 Press any key to continue |
사용자의 재정의가 필요한 복사 생성자
복사 생성자는 컴파일러가 자동으로 생성하기 때문에 동적메모리 할당을 하는 객체의 경우 복사 생성자에 의해 객체를 만들게 되면 동적메모리 할당 해제 시 문제가 발생할 수 있다. 이러한 문제가 발생 될 것이 예상된다면 사용자는 복사 생성자를 직접 만들어 사용할 수 있다.
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
52
53
54
55
56
57
|
//복사 생성자를 직접 정의하여 문제를 해결한 예제
#include <iostream.h>
#include <string.h>
class String{
char *str;
int len;
public:
String(char *); // 생성자
~String(); // 소멸자
void cat(String &); // 전달인자가 객체인 멤버함수
String(const String &tmp); // 복사 생성자 재정의
void prn();
};
String::String(char *p) {
len = strlen(p);
str = new char[len+1];
strcpy(str,p);
}
String::~String() {
cout << "Deleting str...\n";
delete str; // 메모리 해제
}
void String::cat(String &s) {
len = len + s.len;
char *tmp = new char[len+1]; // 메모리 동적할당
strcpy(tmp, str); // 문자열 복사
strcat(tmp, s.str); // 문자열 연결
delete str; // 옛 문자열 해제
str = tmp;
}
//복사 생성자 재정의
//복사 생성자는 이미 만들어진 객체를 레퍼런스변수로 받음
String::String(const String &tmp) {
len = tmp.len;
str = new char[len+1];
strcpy(str, tmp.str);
}
void String::prn() {
cout << "문자열: " << str << "(" << len << ")" << endl;
}
int main()
{
String str1("Object-oriented"), str2(str1);
str1.prn();
str2.prn();
str1.cat(str2);
cout << "\n====문자열 연결====\n");
str1.prn();
return 0;
}
|
cs |
//실행결과 문자열: Object-oriented (16) 문자열: Object-oriented (16) ====문자열 연결==== 문자열 : Object-oriented Object-oriented (32) Deleting str... Deleting str... Press any key to continue |