struct Base {
Base() { std::cout << "Base constructor\n"; }
virtual ~Base() { std::cout << "Base destructor\n"; }
};
→ virtual ~Base()는 가상 소멸자로서 "Base destructor\n"을 출력하도록 초기화되었다.
소멸자는 항상 "파생 클래스 → 부모 클래스" 순서로 호출된다. 이 순서는 가상 소멸자 여부와 관계없이 동일하다. 단, 부모 포인터로 자식 객체를 delete할 경우에는 가상 소멸자가 없으면 자식 소멸자가 호출되지 않는 것이 문제다.
가상 소멸자는 부모 클래스(Base class)의 소멸자를 virtual로 선언한 것이다. 상속받은 클래스 객체를 부모 포인터로 삭제할 때, 자식 클래스의 소멸자가 호출되지 않는 문제를 방지하기 위해 사용한다.
struct Base { ~Base() { std::cout << "Base\n"; } };
struct Derived : Base { ~Derived() { std::cout << "Derived\n"; } };
Base* p = new Derived();
delete p; // ❗ Derived 소멸자 호출 안 됨!
가상 소멸자가 없는 경우 메모리 누수나 리소스 해제가 제대로 되지 않을 수 있다.
| 상황 | 가상 소멸자 필요 여부 | 설명 |
|---|---|---|
new + delete 사용 | ✅ 필수 | 부모 포인터로 자식 객체를 생성 후 삭제할 때 자식 소멸자가 반드시 호출되어야 함 |
| 스택에 생성된 객체 | ❌ 필요 없음 | 객체는 타입에 맞게 자동으로 소멸됨 → 다형성과 무관 |
스마트 포인터 사용 (std::unique_ptr<Base>) | ✅ 필수 | 스마트 포인터가 delete 호출하므로 역시 자식 소멸자까지 필요함 |
| 다형성 안 쓰는 경우 | ❌ 필요 없음 | 자식 타입으로 직접 사용하면 소멸자도 정확히 호출됨 |
가상 소멸자는 "부모 포인터로 자식 객체를 delete할 때" 꼭 필요하다. new/delete, 스마트 포인터와 같이 동적 메모리 해제 시에 특히 중요하다. 스택에 생성된 객체나 다형성을 사용하지 않는다면 가상 소멸자가 없어도 문제 없다.
C++에는 가상 생성자(virtual constructor)는 존재하지 않는다.
생성자는 객체를 생성하는 과정의 일부인데, 객체가 아직 만들어지기 전에는 가상 함수 테이블(vtable)도 존재하지 않기 때문에 다형성(virtual dispatch)을 사용할 수 없다.
즉, "아직 존재하지 않는 객체의 종류를 런타임에 따라 선택"하는 건 논리적으로 불가능하다.