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


시간 기록을 유지하는 클래스


class TimeKeeper{

public:

TimeKeeper();

~TimeKeeper();

...

};


class AtimicClock : public TimeKeeper { ... };

class WaterClock : public TimeKeeper { ... };

class WristWatch : public TimeKeeper { ... };




시간정보에 접근하기 위한 팩토리함수를 선언

TimeKeeper* getTimeKeeper(){ return new 파생 클래스 };


팩토리 함수의 기존 규약을 그대로 따라간다면 이 함수에서

리턴되는 객체는 힙에 있게 된다. 따라서 삭제를 해줘야함.


TimeKeeper *ptk = getTimeKeeper();

...

...

delete ptk;


문제점


getTimeKeeper()에서 리턴되는 포인터가 파생 클래스 객체에 대한

포인터라는 점과 이 포인터가 가리키는 객체가 삭제될 때는

기본 클래스 포인터를 통해 삭제된 다는 점.


--> 기본 클래스의 소멸자가 비가상 소멸자이기 때문에

자기자신만 지우고 파생클래스는 지우지 않는다




C++의 규정에 의하면, 기본 클래스 포인터를 통해 파생 클래스 객체가

 삭제될 때, 그 기본 클래스에 비가상 소멸자가 들어 있으면

 프로그램 동작은 미정의 사항이라고 되어있다.


머리 아프다 맘 편히 정리하자

가상 함수를 하나라도 가진 기본 클래스라면 가상 소멸자를 가져야 한다!




하지만 기본 클래스로 의도하지 않은 클래스에 대해

 소멸자를 가상으로 선언하는 것은 좋지 않다.

가상 함수 테이블 포인터와 가상 함수 테이블에

 대한 얘기가 나오는데, 이 부분은 나중에 다시 심도있게 다루겠다.

 아무튼 기본 클래스가 아니라면 가상소멸자를 쓰지말자.


중간 정리

가상 소멸자를 선언하는 것은 그 클래스에 가상 함수가 하나라도 들어 있는 경우에만 한정하라.




비가상 소멸자의 예 --> 표준 string 클래스


class sss : public string {

...

};


sss* psss = new sss("Good Morning");

string *ps = psss;

delete ps;             --------> sss의 소멸자가 호출되지 않는다.


STL 컨테이너 타입도 비가상 소멸자이다.

따라서 STL을 상속받아서 나만의 클래스를 만드는 것은 금물!

(자바의 final이나 C#의 sealed 클래스는 파생방지 메커니즘이 따로 있다.)




순수 가상 소멸자

어떤 클래스가 추상 클래스였으면 하는데

 마땅히 순수 가상으로 만들 함수가 없을 때

순수 가상 소멸자를 지정해주는 것도 좋은 방법이다.

(추상 클래스 --> 기본 클래스 목적으로 만들어짐.)


주의!

순수 가상 소멸자는 정의를 꼭 두어야 한다.


class sss{


public:

sss();

virtual ~sss();

}

sss::~sss();




소멸자의 동작 순서

상속 계통 구조에서 가장 말단에 있는 파생 클래스의

소멸자가 먼저 호출 되고 점점 올라오면서 차례로 소멸자가 호출된다


컴파일러는 ~sss의 호출 코드를 만들기 위해 파생 클래스의

소멸자를 사용할 것이므로, 잊지 말고 이 함수의 본문을 준비해 두어야

하는 것이다. 이 부분을 잊는다면 링커 에러!




잊지말기

가상 소멸자를 선언해주는 규칙은 다형성을 가진 기본 클래스,

기본 클래스 인터페이스를 통해 파생 클래스 타입의 조작을 허용하도록

설계된 기본 클래스에서만 적용된다는 사실!




기본 클래스의 인터페이스를 통해 파생클래스의 객체 조작이 허용될 때만 가상 소멸자!!

앞서 말한 string과 stl은 다형성을 가지지 않음

그리고 전전 포스팅에서 uncopyable이라는 복사, 대입 금지 클래스를 만들었었다.

기본 클래스로는 쓰이고 있지만 다형성을 가지지 않는 클래스라 말할 수 있다.

이러한 경우도 가상소멸자 안됨~



POINT!!

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

즉, 어떤 클래스가 가상 함수를 하나라도 갖고 있으면, 닥치고 가상 소멸자.


기본 클래스로 설계되지 않았거나 다형성을 갖도록 설계되지 않은 클래스에는

가상 소멸자를 쓰면 안된다!!



+ Recent posts