2016. 4. 20. 13:23


저희가 상속을 사용하여 클래스를 구성할때 최상위 부모 소멸자에는 Virtual을 넣어 주어야 합니다.

그 이유가 뭘까요?

이유를 알기위해선 상속을 받은 클래스의 생성과 소멸의 순서를 알아야합니다.

생성을 할경우 부모클래스의 생성자부터 호출되며 차례로 자식의 생성자를 호출하게 됩니다.

반대로 소멸자는 자식클래스의 소멸자를 먼저 호출하고 부모클래스의 소멸자가 호출됩니다.

이렇게 생각하면 아무런 문제없습니다. 

단, 우리가 비교적 자주 상속을 사용하여 선언할경우 부모클래스의 포인터로 자식클래스를 정의하여 사용하게 될것입니다.

이경우, 부모클래스로부터 자식 클래스를 호출할때 가상 함수로 정의되지 않은 자식 클래스의 오버라이딩된 함수를 호출하면 주체가 선언된 인자형이 부모이기 때문에 부모클래스의 멤버함수가 호출됩니다.

이렇게 생각했을때 소멸자 또한 오버라이딩된 멤버함수라 볼 수 있기 때문에, 만약에 부모 포인터로 객체를 삭제하면 부모클래스의 소멸자가 호출되며 정의된 자식의 나머지 공간의 메모리 만큼 누수되어 버립니다.

따라서 소멸자를 가상 함수로 선언하지 않으면 자식클래스의 소멸자가 결코 호출되지 않습니다. 

virtual을 사용하였다면 이것은 자식클래스에서 재정의 될 수 있음을 명시 하기 때문에 포인터의 종류와 상관없이 자식 클래스의 멤버함수가 호출되게 답니다. 즉, 자식 클래스의 소멸자가 호출되고 부모 클래스의 소멸자가 호출되게 됩니다.

따라서 상속관계를 이용하였고 소멸자에서 리소스를 해제해야 한다면 반드시 소멸자를 가상함수로 선언해주어야 합니다.

예제 코드
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
#include <iostream>
using namespace std;
 
class classA
{
    public:
      classA(){  cout << "A 생성" << endl;}
       virtual ~classA(){  cout << "~A 소멸" << endl;}
};
 
class classB : public classA
{
    public:
      classB(){cout << "B 생성"<< endl;}
      ~classB(){cout << "~B 소멸" << endl;}
};
 
 
int main()
{
  cout << "== 소멸자 테스트 시작 ==" << endl;
  classB *= new classB;
  classA *= B;
  delete A;
  return 0;
}
cs



실행 결과는 다음과 같습니다


ClassA에서 소멸자에 virtual을 사용하지 않았을 경우

===================================================================

START

A

B

~A

===================================================================


ClassA에서 소멸자에 virtual을 사용했을 경우

===================================================================

START

A

B

~B

~A

===================================================================


Posted by 시리시안