Post

[ STUDY/Effective C++ ] 2022. 6. 25. 03:13

다형성을 가진 기본 클래스에서 비가상 소멸자를 통해 소멸하면 어떻게 될까?

class TimeKeeper {
public:
	TimeKeeper();
	~TimeKeeper();
    ...
};
TimeKeeper* getTimeKeeper();
TimeKeeper *ptk = getTimeKeeper();

...
delete ptk;

기본 클래스 포인터를 통해 파생 클래스 객체가 삭제될 때 비가상 소멸자가 들어 있으면, 대부분 그 객체의 파생 클래스 부분이 소멸되지않게 된다.

파생 클래스의 소멸자도 실행되지 않지만 기본클래스 부분은 소멸 과정이 제대로 끝나 '부분소멸'이 되게된다.

 

이 문제를 없애기위해서는 기본 클래스에 가상 소멸자를 넣어놓으면된다.

class TimeKeeper {
public:
	TimeKeeper();
	virtual ~TimeKeeper();
    ...
};
TimeKeeper* getTimeKeeper();
TimeKeeper *ptk = getTimeKeeper();

...
delete ptk;

소멸자 앞에 virtual 만 붙여줄 뿐인데, 파생 클래스 까지 객체 전부가 소멸된다. 

 

 

 

하지만 기본클래스로 설계되지 않거나 다형성을 갖도록 설계되지않은 클래스조차 마구잡이로 가상소멸자를 선언하면 안된다

class Point {
public:
	Point (int xCoord, int yCoord);
	~Point();
    
private:
	int x,y;
};

위와같은 코드가 있을때, Point객체는 int가 2개 있으니 64bit를 생각하면 64bit레지스터에 맞게된다.

하지만 Point 클래스의 소멸자가 가상 소멸자라면 64bit가 아닌 96bit가 된다.(C++에서는 가상함수를 구현하기 위해 클래스에 별도로 가상 함수 테이블 포인터 라는 자료구조가 들어가야하기 때문이다.)

 

그리고 다른 언어로 선언된 동일한 자료구조와도 호환성을 잃게된다. 다른 언어에선 '가상 함수 테이블 포인터' 라는 vptr이 없기때문이다. 

그렇기때문에 가상 소멸자를 선언하는것은 그 클래스에 가상 함수가 하나라도 있을 경우에만 선언하고, 가상 함수가 없을때에는 가상 소멸자를쓰지말자!

 

 

하지만 모든 기본 클래스가 다형성을 갖도록 설계된것은 아니다.

(표준 string타입, STL컨테이너타입)

그리고 기본클래스로는 쓰일 수 있지만, 다형성은 갖지않도록 설계된것도 있다.

(Uncopyable, 표준 라이브러리의 input_iterator_tag)

이런 클래스들은 파생 클래스 객체의 조작이 허용되지 앟기때문에 가상 소멸자를 볼 수 없다.

 

 

 

+) 순수 가상 소멸자를 이용하면 추상클래스를 쉽게 만들 수 있다.

우리가 아는 추상클래스는 보통 순수가상함수가 들어가 있다.

하지만 추상클래스이면 좋겠지만 넣을 순수 가상 함수가 없다면 굳이굳이 만들어서 넣을필요는 없고,

순수 가상 소멸자만 있더라도 추상클래스가 될 수 있다.

class AWOV {
public:
	virtual ~AWOV() =0; //순수 가상 소멸자 선언
};
AWOV:: ~AWOV() {} //순수 가상 소멸자 정의
▲ top