본문 바로가기
책 정리/Effective C++ 3rd

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

by ocean20 2019. 10. 22.

1. 팩토리함수
  - 정의 : (생성된 파생클래스 객체)를 가리키는 (기본클래스의 포인터)를 반환하는 함수
  - 유의할점 : 파생클래스의 객체를 new로 할당하기때문에 메모리를 적절히 삭제해야한다.
  * 문제가 되는 코드를 살펴보자.

class product{ 
public: 
virtual void print() = 0; 
}; 
  
class concreteProduct : product{ 
public: 
void print() override{ cout<< "concreteProduct"<<endl; } 
}; 
  
class Creator{ 
public: 
Product* AnOperation() { return factoryMethod(); } 
  
protected: 
virtual Product* factoryMethod() = 0 ; 
}; 
  
class ConcreteCreator : Creator{ 
private: 
Product* factoryMethod() { return new ConcreteProduct;} 
}; 
  
  
int main() 
{ 
ConcreteCreator* cc ; 
Product* product = cc.AnOperation(); // 기본클래스product 포인터가 파생클래스 ConcreteProduct객체를 가리킨다 
product->print(); 
  
delete product; // 기본클래스를 통해 파생클래스의 메모리를 삭제한다. 
} 

* 풀이
  - main함수의 2번째줄을 보면 (기본클래스의 포인터)가 (파생클래스의 객체)를 가리킨다. 
  - main함수의 4번째줄 처럼, 기본클래스의 포인터를 사용하여  파생클래스 객체메모리를 해제한다면, 오류가 발생한다. (c++ 규정이 그러하다.)
  - 오류내용 : 기본클래스에 가상소멸자가 없을경우, 다형성의원리로 인해, 파생객체의 메모리가 해제 되지않는다. 파생클래스로 만들어진 객체의 소멸자가 호출 되지 않음

2. 결론
- 기본클래스(ex. Product)의 소멸자를 가상으로 선언하여 위 문제를 해결한다.
- 기본클래스가 가상멤버함수를 하나라도 가지고 있다면, 가상소멸자도 가져야한다.


3. 의문점
  - 질문 : 만약, 기본클래스(추상화클래스)역할을 수행하지않는 부모클래스(가상함수가 없는클래스)에서 소멸자를 가상으로 선언할경우에는 어떨까?
  - 답변 : 가상소멸자를 선언해준 경우, 해당함수를 호출하기위해서 Vptr이라는 녀석이 필요한데 이녀석도 포인터이기에 32비트 시스템에서 4바이트를 차지한다. 따라서 다른언어로 만들어진 소스의 해당 객체를 넘길시 vptr도 같이넘어가기때문에 이식성은 포기해야한다.

4. 정리
  - 가상소멸자는 해당클래스가 가상함수를 가질때만 사용하자.


5. 추상클래스에서 순수가상함수를 쓰지 않을 경우
  - 이 경우, 순수 가상소멸자를 선언 및 정의를 해줘야한다. --> 왜? 파생클래스가 임무를 마치고 메모리 해제 될때, 해제순서가 파생클래스 ->기본클래스 순이다. 기본클래스의 가상소멸자가 선언만 있고 정의는 없을경우, 호출이 불가능하므로 , 선언 그리고 정의도 해주어야 한다.


이것만은 잊지말자 !
  - 다형성을 가진 기본 클래스에는 반드시 가상 소멸자를 선언해야 한다. 즉, 어떤 클래스가 가상함수를 하나라도 갖고 있으면, 이클래스의 소멸자도 가상 소멸자이어야 한다.
  - 기본 클래스로 설계되지 않았거나 다형성을 갖도록 설계되지 않은 클래스에는 가상 소멸자를 선언하지 말아야 한다.

댓글