티스토리 뷰

반응형

다형성을 가진 기본 클래스에서는 소멸자를 반드시 가상 소멸자로 선언하자

함수가 반환하는 포인터가 파생 클래스 객체에 대한 포인터라는 점과 
이 포인터가 가리키는 객체가 삭제될 때는 기본 클래스 포인터를 통해 삭제 된다는 점, 
그리고 결정적으로 기본 클래스에 들어 있는 소멸자가 비가상 소멸자 라는 점이다.

C++ 의 규정에 의하면, 
기본 클래스 포인터를 통해 파생 클래스 객체가 삭제될 때 그 기본 클래스에 비가상 소멸자가 들어 있으면 프로그램 
동작은 미정의 사항이라고 되어 있다.

 

예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class TimeKeeper
{
public:
    TimeKeeper();
    ~TimeKeeper();
};
 
void main()
{
    TimeKeeper *ptk = getTimeKeeper();
 
    //-------------------------------------------
    // TODO: 
    
    delete ptk;                                 
}
cs


GetTimeKeeper 함수에서 포인터를 통해 날아오는 AtomicClock 객체는 기본 클래스 포인터를 통해 삭제 될 때
AtomicClock부분(AtomicClock 클래스에서 정의된 데이터 맴버들)이 지워지지 못할 뿐만 아니라 AtomicClock 의 소멸자도 실행되지 않는다. 
그러나 기본 클래스 부분(즉, TimeKeeper 부분)은 소멸 과정이 제대로 끝나므로 결국 반쪽짜리 부분 소멸 객체의 신세가 된다.

 

해법

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class TimeKeeper
{
public:
    TimeKeeper();
    virtual ~ TimeKeeper();
};
 
void main()
{
    TimeKeeper *ptk = getTimeKeeper();
    //------------------------
    // TODO:
 
    delete ptk;    
}
cs



해법 : 기본 클래스에게 가상 소멸자를 선물하자. Virtual 하나 붙여 줬을 뿐인데 객체 전부가 소멸된다. 

파생 클래스 부분까지 몽땅.
TimeKeeper 비슷한 기본 클래스에는 대개 소멸자 외에도 가상 맴버 함수들이 더러 들어 있게 마련이다. 
파생 클래스를 구현할 때 해당 함수를 역할에 따라 맞추는 작업을 허용한다는 의미임.

예를 들어, TimeKeeper 클래스는 현재 시각을 알려 주는 getCurrentTime 함수를 가상 함수로 가질 수 있습니다. 
이 함수는 여러 파생 클래스에서 다른 의미로 구현 되겠지요.

사정이야 어쨌든, 가상 함수를 하나라도 가진 클래스는 가상 소멸자를 가져야 하는 게 대부분 맞습니다.
가상 소멸자를 선언하는 것은 그 클래스에 가상 함수가 하나라도 들어 있는 경우에만 한정하세요.

추상 클래스는 본래 기본 클래스로 쓰일 목적으로 만들어진 것이고, 기본 클래스로 쓰이려는 클래스는 가상 소멸자를 가져야 합니다. 한편 순수 가상 함수가 있으면 바로 추상 클래스가 됩니다. 결론은 추상 클래스로 만들고 싶은 클래스에 순수 가상 소멸자를 선언하는 것입니다.


Ex) AWOV : : ~ AWOV( ) { }       // 순수 가상 소멸자의 정의

 

결론

다형성을 가진 기본 클래스에는 반드시 가상 소멸자를 선언해야 합니다. 

즉, 어떤 클래스가 가상 함수를 하나라고 갖고 있으면, 이 클래스의 소멸자도 가상 소멸자이어야 합니다.
기본 클래스로 설계되지 않았거나 다형성을 갖도록 설계되지 않은 클래스에는 가상 소멸자를 선언하지 말아야 합니다. 

반응형
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/04   »
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
글 보관함