일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- Deque
- queue
- list
- map
- C언어
- set
- 아두이노
- LineTracer
- c++
- stl
- 시스템프로그래밍
- 통계학
- Algorithm
- 수광 소자
- 운영체제
- Stack
- priority_queue
- arduino compiler
- WinAPI
- 자료구조
- html
- 컴퓨터 그래픽스
- 아두이노 소스
- Arduino
- vector
- directx
- 아두이노 컴파일러
- 라인트레이서
- Array
- Visual Micro
- Today
- Total
Kim's Programming
C++ - 클래스 생성자/파괴자(1/3) 본문
생성자/파괴자의 특징
클래스는 단순 타입보다 훨씬 더 복잡한 정보를 다룰 수 있기 떄문에 대입문 같은 간단한 형식으로는 초기화할 수 없습니다. 그래서 생성자라는 특별한 멤버 함수가 고유한 초기화를 수행하는데 초기화가 워낙 특수하기 떄문에 뒷처리하는 파괴자라는 것도 필요합니다. 생성자와 파괴자는 컴파일러에 의해 자동으로 호출되며 임무 자체가 특수해서 일반 함수와는 다른점도 있고 주의사항도 많습니다. 다음 것들은 생성자와 파괴자의 특징입니다.
- 이름이 정해져있습니다. 생성자의 이름은 클래스의 이름과 같고 파괴자의 이름은 클래스 이름 앞에 ~를 붙입니다. 클래스 이름이 MyClass라면 생성자의 이름은 MyClass()이고 파괴자의 이름은 예외없이 ~MyClass()입니다. 일반 함수처럼 사용자가 이름을 정할 수 없는 이유는 생성자와 파괴자는 사용자가 호출하는 것이 아니라 컴파일러에 의해서 자동으로 호출하기 떄문입니다. 사용자가 마음대로 이름을 붙이게 되면 컴파일러는 생성자, 파괴자를 찾지 못할 것입니다. 그러므로 클래스의 이름으로 생성자, 파괴자를 생성하게됩니다.
- 리턴값이 없습니다. 생성자와 파괴자의 임무는 초기화 및 정리를 하는 것이지 어떤 값을 조사하거나 계산하는 것이 아니므로 리턴할 대상이 없습니다. 설사 리턴대상이 있다고 하더라도 이 두 함수들은 자동으로 호출되기 떄문에 리턴을 받아줄 주체가 없습니다. 굳이 일반 함수에 비유하면 void형이라고 할 수 있는데 void형이라고 선언하게 되면 에러 처리가 됩니다. 그래서 생성자와 파괴자의 원형은 타입없이 바로 함수의 이름을 씁니다. 파과자와, 생성자에겐 리턴이란 개념 자체가 없습니다.
- 반드시 public 액세스 속성을 가져야 합니다. 객체를 생성하고 사용하고 파괴하는 주체는 자신이 아니기 떄문에 외부에서 생성자, 파괴자를 호출할 수 있어야합니다. 생성자, 파괴자가 숨겨져있는 클래스를 선언하는것 자체는 가능하지만 이렇게 선언된 클래스를 의 인스턴스를 만들 수는 있으며 특수한 목적에만 사용됩니다. 만약 생성자가 숨겨진 클래스의 객체를 선언하면 컴파일 에러로 처리됩니다.
- 생성자는 인수가 있지만 파괴자는 인수가 없습니다. 생성자는 객체의 멤버를 초기화하는데 어떤 값으로 초기화를 할 것인지는 지정해야 하며 그래서 인수가 필요합니다. 인수를 가지기 때문에 오버로딩이 가능하며 인수의 개수와 타입이 다른 여러 개의 생성자를 동시에 정의할 수 있습니다. 객체를 초기화하는 방법의 개수만큼 생성자를 제공할 수 있으며 흔히 그렇게 합니다. 반면 객체를 파괴할 때는 객체가 할당한 메모리, 열어놓은 파일등을 무조건 다 정리해야 하며 파괴에 대한 선택 사항은 있을 수 없습니다. 파괴자가 해야 할 일은 클래스를 만들 때 이미 정해진것이므로 별도의 인수를 전달받을 필요가 없는 것입니다. 파괴자가 해야 할 일은 클래스를 만들 때 이미 정해진 것이므로 별도의 인수를 전달받을 필요가 없는 것입니다. 인수가 없으므로 오버로딩도 할 수 없으며 클래스당 파괴자는 하나만 존재합니다. Position 클래스의 파괴자는 무조건 ~Position()하나 뿐입니다. 설사 파괴자가 인수를 받아들인다 하더라도 객체가 파괴될 때 자동으로 호출되는 파괴자에게 인수를 전달할 기회는 없습니다.
- friend도 static도 될 수 없습니다. 생성자, 파괴자는 둘 다 클래스 내부의 함수이므로 friend 지정이 없어도 멤버를 마음대로 액세스할 수 있습니다. 또한 초기화와 정리의 대상이 클래스가 아니라 개별 객체이므로 static일 필요도 없습니다.
- 파괴자는 가상 함수로 정의될 수 있지만 생성자는 가상함수로 정의될 수 없습니다. 상속의 이점을 충분히 활용하기 위해서 파괴자는 가상 함수로 선언하는 것이 좋습니다. 하지만 아직 만들어지지 않은 객체에 대해 다형적인 특성을 사용할 수는 없으므로 생성자는 가상함수가 될 수 없습니다.
- 둘 다 디폴트가 있습니다. 디폴트 생성자는 인수를 취하지 않고 아무런 동작도 하지 않으며 디폴트 파괴자 역시 아무 동작도 하지 않습니다. 디폴트가 있기 떄문에 특별히 초기화할 내용이 없거나 정리할 필요가 없다면 생성자, 파괴자를 일부러 만들지 않아도 상관없습니다.
실행 중에 객체를 동적으로 생성할 때는 new 연산자를 사용합니다. new 연산자는 객체를 위한 메모리를 할당한 후 생성자를 호출하므로 동적 할당문에 생성자가 요구하는 인수를 전달하여야 합니다. 앞의 소스에 다음 소스를 추가해보겠습니다.
1 2 3 4 5 6 7 8 9 10 | void main() { Person Per("홍길동", 23); Per.OutPerson(); Person *pe; pe = new Person("동길홍", 30); pe->OutPerson(); delete pe; } | cs |
new연산자로 Person형의 객체를 동적으로 생성하되 생성자로 ("동길홍",30)의 인수를 전달했습니다. new 연산자는 Person 클래스의 크기만큼 메모리를 할당하고 Person(char *,int) 생성자를 호출하여 이 객체를 초기화할 것입니다. 생성자의 new 연산자는 인수로 전달받은 문자열을 저장할 만큼 메모리를 동적 할당하여 Name 멤버에 대입합니다. 초기화가 완료된 후 새로 생성된 객체 포인터가 티턴되는데 이 포인터를 Person *형 pe라는 변수에 대입했습니다. 다음 코드와 의미가 같습니다.
1 2 3 4 | int *pi; pi=new int(1234); cout << *pi; delete pi; | cs |
타입이 int가 아닌 사용자 정의형이라는 것 외에는 똑같은 문장입니다. pe 포인터가 동적으로 생성된 Person 객체를 가리키고 있으면 이 포인터를 사용하여 객체를 프로그래밍할 수 있습니다. pe->OutPerson()은 pe이 가리키는 객체의 정보를 화면으로 출력할 것입니다. 다 상용한 객체는 delete 연산자로 파괴하는데 이 연산자는 먼저 파괴자를 호출합니다. 파괴자는 생성자가 할당 해 놓은 메모리를 해제하며 delete 연산자는 객체 그 자체를 메모리에서 해체합니다. 객체 그 자체도 힙에 생성되지만 객체가 사용하는 메모리도 힙에 생성됩니다. 동적 할당의 대상이 객체일 떄는 반드시 생성자를 호출하는 new 연산자를 사용해야 합니다. 객체가 생성 및 파괴될 때 어떤 일들이 일어나는지 확인해보기 위해 생성자와 파괴자에 printf로 간단한 메세지를 출력해보겠습니다.
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 | #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<string.h> using namespace std; class Person { private: char *Name; int Age; public: Person(const char *aName, int aAge) { Name = new char[strlen(aName) + 1]; strcpy(Name, aName); Age = aAge; cout << Name << " 객채 생성자 호출! " << endl; } ~Person() { cout << Name << " 겍채 파괴! " << endl; delete[] Name; } void OutPerson() { cout << " 이름 : " << Name << " 나이 : " << Age << endl; } }; void main() { Person Per("홍길동", 23); Per.OutPerson(); Person *pe; pe = new Person("동길홍", 30); pe->OutPerson(); delete pe; } | cs |
실행 결과는 다음과 같습니다.
정적으로 생성되는 객체이든, 동적으로 생성되는 객체이든 생성자와 파괴자가 모두 호출된다는 것을 확인 할 수 있습니다. 어떤 함수가 언제 호출되는지 정확한 시점과 회수를 알고 싶으면 이런식으로 문자열을 중간마다 출력시켜 주면 됩니다. 이 코드를 수정하여 malloc으로 객체를 생성하기 위해서는 다음과 같이 할 수 있습니다.
1 2 3 4 | Person *per; per=(Person *)malloc(sizeof(Person)); per->OutPerson(); free(per); | cs |
이렇게 하면 객체를 위한 메모리만 할당될 뿐 객체가 사용하는 메모리를 할당되지 않습니다. malloc은 단순한 메모리 할당 함수일 뿐이므로 지정한 바이트수 만큼 메모리만 할당하며 생성자를 호출하ㄹ거나 하지는 않습니다. per이 가리키는 곳에 Person 클래스의 크기만큼 메모리가 할당되어 있기는 하지만 Name이나 Age는 쓰레기값을 가지고 있을 것입니다. OutPerson은 이 두 값을 화면으로 출력하는데 Name이 가리키는 메모리 영역이 어디인지 알 수 없으므로 다운될 확률이 아주 높습니다. malloc이 생성자를 호출하지 않는 것과 마찬가지로 free는 파괴자를 호출하지 않습니다. 객체를 동적할당 할때는 반드시 new/delete 연산자를 사용하여 생성자와 파괴자를 적절하게 호출하도록 해야합니다. malloc/free는 단순 메모리를 할당할 때만 쓸 수 있는데 Person 생성자에서 Name을 위한 메모리를 할당할 때는 이 함수들을 사용할 수 있습니다. 이름 문자열 저장을 위한 버퍼를 malloc으로 할당하도록 수정해보겠습니다.
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 | #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<string.h> using namespace std; class Person { private: char *Name; int Age; public: Person(const char *aName, int aAge) { Name = (char *)malloc(strlen(Name)+1); strcpy(Name, aName); Age = aAge; cout << Name << " 객채 생성자 호출! " << endl; } ~Person() { cout << Name << " 겍채 파괴! " << endl; free(Name); } void OutPerson() { cout << " 이름 : " << Name << " 나이 : " << Age << endl; } }; void main() { Person Per("홍길동", 23); Per.OutPerson(); Person *pe; pe = new Person("동길홍", 30); pe->OutPerson(); delete pe; } | cs |
Name 버퍼는 단순한 문자열에 불과하므로 이 배열을 할당할 때는 굳이 new,delete를 사용하지 않아도 문제가 없습니다. 그러나 두 방법을 섞어서 쓰다보면 실수할 가능성이 있어 new, delete로 할당하는게 좋습니다.
여러 가지 생성자
디폴트 생성자
디폴트 생성자(떠는 기본 생성자라고도 하는)란 인수를 가지지 않는 생성자입니다. 생성자는 오버로딩이 가능하므로 여러 개를 둘 수 있는데 그 중 인수가 없는 생성자를 디폴트 생성자라고 부릅니다. 즉 인수 목록이 void인 생성자인데 Position 클래스의 경우 디폴트 생성자의 원형은 Position()이 됩니다. 다음 예제의 Position 클래스 생성자 하나만 정의하고 있습니다.
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 | #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<string.h> #include<Windows.h> using namespace std; void gotoxy(int x, int y) { COORD CursorPosition = { x, y }; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), CursorPosition); } class Position { private: int x; int y; char ch; public: Position() { x = 0; y = 0; ch = ' '; } void Outposition() { if (ch != ' ') { gotoxy(x, y); putchar(ch); } } }; void main() { Position posit; posit.Outposition(); } | cs |
디폴트 생성자는 호출부에서 어떤 값으로 초기화하고 싶은지를 전달하는 수단인 인수가 없습니다. 인수를 받아들이지 않기 떄문에 객체의 멤버에 의미있는 어떤 값을 대입하지는 못하며 주로 모든 멤버를 0이나 -1 또는 NULL이나 빈 문자열로 초기화합니다. 여기서 0이라는 값은 실용적인 의미를 가지는 값이라기보단 단순히 아직 초기화되지 않았음을 분명히 표시하는 역할을 합니다. 어떤 값인지 알지도 못하는 쓰레기 값보다는 그래도 0을 대입해놓는게 낫은데 이렇게 하면 멤버 함수에서 이 값을 사용하기 전에 초기화되어 있는지를 점검할 수 있기 떄문입니다.
1 2 | if(ptr==NULL){} if(value==0){} | cs |
디폴트 생성자가 포인터 변수를 NULL로 초기화해 놓으면 멤버 함수가 이 변수를 사용하기 전에 NULL인지 조사해보고 NULL이면 그때 초기화를 할 수 있습니다. 즉 디폴트 생성자의 임무는 쓰레기를 치우는 것이지 멤버의 초기화는 이 멤버를 사용하는 멤버 함수가 호출될 때 까지 연기됩니다. 위 소스의 Position() 디폴트 생성자는 x,y는 0으로 초기화하고 ch에는 공백 문자를 대입하며 OutPosition함수는 ch가 공백 문자를 가질 때 이 객체가 초기화되지 않은 것으로 판단하고 문자 출력을 하지 않습니다. 디폴트 생성자가 있는 객체를 선언할 때는 다음과 같은 여러가지 방법을 이용할 수 있습니다.
1 2 3 4 5 | Position Posit; Position Posit=Position(); Position *pPosit=new Position; Position *pPosit=new Position(); Position Posit(); | cs |
첫 번째 형식이 가장 간단하며 위에서 사용한 방법입니다. 생성자에게 전달할 인수가 없으므로 타입 다음에 객체 이름만 밝히면 됩니다. 기본 타입의 int i; 선언문과 형식이 동일합니다. 두 번째 형식은 디폴트 생성자를 명시적으로 호출하는 구문인데 효과는 동일합니다. 세 번쨰, 네 번째는 객체를 동적으로 생성할 때 new 연산자와 함께 사용하는 방법인데 세 번째가 더 일반적입니다. 하지만 다섯 번째 형식은 허용되지 않습니다. 왜냐하면 이 선언문은 Position 객체를 리턴하고 인수를 가지지 않는 Posit함수의 원형을 선언하는 것이지 객체 선언문이 아니기 때문입니다. 생성자로 전달 인수가 없으면 아예 괄호가 없어야합니다. 일반 함수는 인수가 없을 때 빈 괄호를 써 함수임을 분명히 표시하지만 객체 선언문의 경우는 반대로 생성자의 인수가 없을 때 괄호를 생략해 함수가 아님을 분명히 해야 합니다. 정수로 바꿔 생각하면 다음과 같습니다.
1 2 | int Posit() //함수 int Posit //변수 | cs |
만약 클래스가 생성자를 전혀 정의하지 않으면 어떻게 될까요? 이 경우 컴파일러가 자동으로 디폴트 디폴트 생성자를 만듭니다. 컴파일러가 만들어 주는 디폴트 생성자는 아무 것도 하지 않는 빈 함수입니다. 이 때 객체의 초기화 방식은 일반 변수와 같은 규칙이 적용되는데 전역이나 정적 객체라면 모든 멤버가 0으로 초기화되고 지역 객체라면 초기화되지 않는 쓰레기값을 가집니다. 생성자가 없을 경우 컴파일러가 디폴트 생성자를 만들기 때문에 생성자를 전혀 정의하지 않아도 객체를 선언할 수 있는 것입니다. 위 소스에서 Position()디폴트 생성자를 삭제하면 컴파일러가 내부적으로 다음과 같은 디폴트 생성자를 만들 것입니다.
1 2 3 | Position() { } | cs |
비록 아무 것도 하지는 않지만 생성자가 있으므로 Position Posit; 선언문으로 Posit 객체를 선언할 수 있습니다. 그러나 이 객체는 쓰레기 값을 가지고 있기 떄문에 OutPosition이 어떤 동작을 할 것인지는 예측이 불가능합니다. 일반적으로 예측할 수 없는 동작은 항상 잠재적인 말썽의 기회가 되고 이런것을 없애기 위해 디폴트 생성자를 직접 정의하고 모든 멤버의 쓰레기를 치우는 것입니다. 컴파일러가 디폴트 생성자를 만드는 경우는 클래스가 생성자를 전혀 정의하지 않을 때뿐입니다. 다른 생성자가 하나라도 정의되어 있으면 컴파일러는 디폴트 생성자를 만들지 않습니다. 다음 소스를 통해보자면
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | class Position { public: int x; int y; char ch; Position(int ax, int ay, char ach) { x = ax; y = ay; ch = ach; } void Outposition() {..} } | cs |
정수 하나를 인수로 취하는 생성자가 정의되어 있는 클래스는 디폴트 생성자를 가지지 않습니다. 이 경우 Position Posit; 선언문은 적절한 생성자를 찾을 수 없다는 에러 처리가 됩니다. 별도의 생성자를 제공했다는 것은 클래스를 만든 사람이 이 객체는 이런 식으로 초기화해야 한다는 것을 분명히 명시한 것이므로 컴파일러는 이 규칙을 어긴 코드에 대해 에러로 처리합니다. 이 객체는 개발자의 의도에 따라 반드시 Position Posit(12);형식으로 생성해야 합니다. 만약 Position Posit; 형태로 꼭 객체를 선언하고 싶다면 Position(int) 생성자를 없애 컴파일러가 디 폴트 생성자를 만들도록 내버려 두든가 아니면 Position() 디폴트 생성자를 오버로딩 해야합니다. 생성자가 인수를 가지고 있더라도 디폴트 인수 기능에 의해 디폴트 생성자가 되는 경우도 있습니다. 다음과 같은 원형을 가지는 생성자는 인수없이도 호출할 수 있으므로 디폴트 생성자를 겸합니다.
1 | Position(int ax=0,int ay=0, char ach=' ') | 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 36 | #define _CRT_SECURE_NO_WARNINGS #include<iostream> #include<string.h> #include<Windows.h> using namespace std; void gotoxy(int x, int y) { COORD CursorPosition = { x, y }; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), CursorPosition); } class Position { public: int x; int y; char ch; Position(int ax, int ay, char ach) { x = ax; y = ay; ch = ach; } void OutPosition() { gotoxy(x, y); putchar(ch); } }; void main() { Position Posit[3]; } | cs |
이 소스의 Position 클래스는 디폴트 생성자를 정의하지 않았으며 세 개의 인수를 취하는 생성자만 정의되어 있습니다. 개발자가 별도의 생성자를 정의했으므로 컴파일러는 디폴트 생성자를 만들지 않습니다. 따라서 Position 형의 객체를 만드려면 Position A{1,2,'A'}; 식으로 생성자에게 세 개의 인수를 전달해야합니다. 그렇다면 main함수의 Position Posit[3]은 어떻게 처리될까요? Position형의 객체 3개를 배열로 생성하되 이때 각 객체의 생성자가 호출될 것입니다. 그러나 선언문에 인수가 없기 떄문에 호출할만한 생성자를 찾을 수 없으며 에러로 처리됩니다. Position Posit[3]];선언문이 처리되려면 인수를 취하지 않는 디폴트 생성자가 반드시 있어야 하는 것입니다. 다음과 같은 선언문이 가능하리라 생각해 볼 수도 있습니다.
1 | Position Posit[3]={{1,2,'x'},{3,4,'y'},{5,6,'z'}}; | cs |
구조체 배열처럼 ={}다음에 각 배열 요소의 초기값을 나열하는 형식입니다. {1,2,'x'} 초기식에 있는 값을 클래스 선언문에 나타나는 멤버의 순서대로 대입하면 될 것처럼 보입니다. 객체 배열을 초기화할 때도 이런 문법이 지원된다면 좋겠지만 이 문장은 에러로 처리됩니다. 왜 컴파일러가 객체 배열에 대한 이런 편한 초기식을 지원하지 못하는지 보겠습니다.
객체는 단순히 정보의 집합인 구조체보다는 훨씬 더 복잡하기 떄문에 단순한 대입만으로는 초기화할 수 없습니다. 생성 단계에서 둘 이상의 입력값을 계산한 결과가 초기값이 될 수도 있고 Person 예제처럼 인수의 길이만큼 메모리를 동적으로 할당해야 하는 경우도 있습니다. 또한 멤버가 프라이빗 영역에 있을 경우 외부 선언문에서 함부로 멤버값을 변경하는 것도 허락되지 않습니다. 이런 능동적인 동작을 하려면 결국 객체 초기화를 위해 생성자가 호출되어야 하는 것입니다.
그렇다면 초기식의 값을 그대로 생성자의 인수로 전달하면 되지 않을까요? 초기식에 {1,2,'x'}라고 되어 있으니 Position(1,2,'x') 생성자를 호출하면 일단 될 것처럼 보이지만 이것도 불가능합니다. 왜냐하면 생성자가 반드시 모든 멤버를 선언된 순서대로 다 받아들여야 한다는 제약이 없기 때문입니다. Position(char ach, int ax, int ay) 이런 식으로 생성자가 정의되어 있다면 컴파일러가 초기식의 값과 생성자 인수와의 대응관계를 잘못 판단하게 될 것이고 객체는 제대로 초기화 되지 않습니다.
그렇기 떄문에 컴파일러는 애매한 초기식으로부터 대충 비슷해 보이는 생성자를 호출하는 쓸데없는 서비스를 하기보다는 차라리 에러로 처리하는 것이 더 좋다고 판단하는 것입니다. 만약 객체의 배열을 선언하면서 각 객체를 초기화 해야 겠다면 다음과 같이 일일이 생성자를 호출해야합니다.
1 2 3 4 5 6 7 8 9 10 | void main() { int i; Position Posit[3] = { { 1, 2, 'x' }, { 3, 4, 'y' }, { 5, 6, 'z' } }; for (i = 0; i < 3; i++) { Posit[i].OutPosition(); } } | cs |
이 선언문은 초기식에서 명시적으로 생성자를 호출했고 생성자로 전달되는 인수의 순서를 컴파일러가 분명하게 알 수 있으므로 문법적으로 문제도 없고 애매하지도 않습니다. 객체 배열을 선언하면서 초기화할 때는 이 방법이 정석이며 초기식없이 선언만 하려면 반드시 디폴트 생성자가 정의되어 있어야 합니다. 생성자가 없을 때 컴파일러가 디폴트를 만드는 것처럼 파괴자의 경우와 마찬가지로 아무 일도 하지 않는 빈 함수입니다. 그래서 뒷정리를 할 필요가 없는 클래스라면 디폴트 파괴자를 그냥 사용하는 것도 가능합니다. 즉 파괴자가 없어도 된다는 이야기인데 사실 파괴자는 필요없는 경우가 훨씬많습니다. 생성자가 특별한 처리를 하지 않고 단순히 멤버 변수에 값만 대입함다면 뒷정리를 할 필요가 없습니다. Position은 파괴자가 전혀 불필요한 클래스입니다.
'Programming > Cplusplus' 카테고리의 다른 글
C++ - 클래스 생성자/파괴자(3/3) (0) | 2015.09.03 |
---|---|
C++ - 클래스 생성자/파괴자(2/3) (2) | 2015.08.31 |
C++ - 파괴자(Destructor) (0) | 2015.08.30 |
C++ - 생성자(Constructor) (0) | 2015.08.29 |
C++ - 클래스(Class)(2/2) (0) | 2015.08.28 |