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 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | #include <iostream> using namespace std; class A{ public: A(){cout<<"A생성자 호출"<<endl;} /*virtual*/ ~A(){ cout<<"A소멸자 호출"<<endl; } }; class B : public A { public: int bb; B(){cout<<"B생성자 호출"<<endl;} ~B(){cout<<"B소멸자 호출"<<endl;} }; class C : public B { public: int cc; C(){cout<<"C생성자 호출"<<endl;}; ~C(){cout<<"C소멸자 호출"<<endl;}; }; int main() { // C * c = new C(); // delete c; /** 생성자호출 * C클래스로 할당하였으므로, B로 할당하면 B부터 * C클래스 생성자로 들어가보니 B클래스를 상속받아서 B클래스를 들어가보니 * A클래스를 상속받았으므로 A클래스의 생성자를 호출후 지금까지 호출된 + 생성자들각각 호출해주니 a->b->c * a(생) -> b(생) -> c(생) */ /** 소멸자호출 * C클래스 였기때문에 상속받은 순서반대로 * 즉! C클래스를 삭제하였으니까 C소멸자를 먼저호출하고나서, * 들어가보니 B클래스를 상속받았으니까 B클래스 소멸자를 호출 * 그다음에 A소멸자를 호출 * c(소)-> b(소) -> a(소) */ //----------------------------------------------------------------------------- // A * a = new C(); // delete a; /** 생성자호출 * 이것도 위와 마찬가지로 C클래스로 항당하였으므로 * 상속받은 부모클래스를 차례대로 들어가게되고 끝까지 들어가서 생성자를 * 호출하면서 C클래스 생성자까지 내려오게된다. * a(생성자)-> b(생성자)-> c(생성자) */ /** 소멸자호출 * 이부분이 중요 * A클래스를 삭제하였기때문에 먼저 A클래스의 소멸자를 호출하는데 * A클래스는 상속받은게 없고 virtual 키워도로 소멸자가 감싸지도 * 않았기때문에 소멸자는 a(소멸자) 한번만 호출되어 메모리누수 * 해결방법은 A클래스의 소멸자에 virtual 키워드를 붙이는것으로 해결 * A클래스 소멸자를 봤더니 virtual이다 하면, A클래스를 상속받은 자식 * 소멸자에게 내려가게되고, 그자식도 virtual의 속성을 물려받게 되며, * 그자식을 상속받은 자식까지 계속 있을때까지 내려가게되서 * 마지막 소멸자부터 호출하게 된다. 그리고 호출스택에 쌓인 생성자 * 들을 차례차례 호출함으로써 끝이난다. * c(소멸자)->b(소멸자)->a(소멸자) */ //-------------------------------------------------------------------------- B * b = new C(); delete b; /** 생성자호출 * 이것또한 위와 같다. C클래스로 할당하였으니까 * a(생성자)->b(생성자)->c(생성자) */ /** 소멸자호출 * B클래스 소멸자를 봤더니 A클래스를 상속받았으므로 B소멸자를 * 호출하고 나서, A클래스의 소멸자를 호출하게 된다. * 이렇게 되면, C클래스의 소멸자가 호출되지 않아 메모리 누수 * 해결방법은 B클래스의 생성자나 A클래스 소멸자에게 virtual * 키워드를 붙이게되면, 자동으로 클래스를 상속받은 자식들은 * virtual을 상속받게되어 모든 소멸자가 호출된다. * B클래스의 소멸자에 virtual을 붙이는경우는 * B클래스의 소멸자를 들어가보니 virtual 이라서 B클래스를 상속받은 * 자식을 찾아 내려가게되고, 여기서는 C클래스 소멸자이므로, C까지 * 내려와서 C부터 소멸자를 호출하고, 호출스택에 쌓인 소멸자를 하나하나 * 빼호출하므로, c(소멸자)->b(소멸자)->a(소멸자) */ system("pause"); return 0; } |
클래스 B는 A를 상속받았기때문에
부모는 자식으로 생성가능하고,
이때 부모를 소멸시, 부모에 가상소멸자가 아니면, 자식의 소멸자는 호출되지 않는다. 메모리 누수
또한
B * b = new B(); 는 자식을 delete하면 부모의 가상소멸자 상관없이 상속받은 base클래스의 소멸자까지 호출합니다.
virtual 키워드는 부모클래스에 적용됩니다.
-주의-
무조건 소멸자에 virtual을 붙이는건 안좋음
- virtual함수가 있으면 vptr(가상 함수 테이블 포인터)가 발생하기 때문에 용량이 커지고 다른 언어와의 호완성이 떨어지게 된다.
여러 클래스로 파상되는 기본 클래스 일때는 소멸자에 virtual을 붙여야 함
- 그렇지 않으면 파생된 클래스를 삭제 할때 기본 클래스의 소멸자만 호출이 되서 파생된 부분은 삭제도 못하고 그대로 남는다.
- 가상 소멸자가 안붙으면 기본 클래스로 쓸 생각이 없는것으로 판단하는게 좋음
가상 소멸자가 없는 클래스는 상속받으면 무지 위험해짐
- class SpecialNode : public Node //이 때 Node는 가상 소멸자가 없다고 하자
- SpecialNode *pSN = new SpecialNode("일단은 아무 내용");
- Node * pNode;
- pNode = pSN;
- delete pNode; //이상황에서 메모리가 제거 되는건 Node의 메모리만 제거됨
- STL컨테이너 들은 전부 가상 소멸자가 없으니 조심
'0x0001 > C, C++' 카테고리의 다른 글
[C++] 템플릿 (함수템플릿, 클래스템플릿) (0) | 2019.02.08 |
---|---|
[C++] 연산자 오버로딩 (0) | 2019.02.08 |
[C언어] 10진수를 2진수로 (0) | 2019.02.08 |
[C언어] 최대공약수, 최소공배수 (0) | 2019.02.08 |
[C언어] 문자열 i am a boy -> yob a ma i -> boy a am i 변환 (0) | 2019.02.08 |