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컨테이너 들은 전부 가상 소멸자가 없으니 조심

 

 

+ Recent posts