C++객체지향

virtual destructor와 object slicing

다형성을 쓰는 기반 클래스에서 왜 virtual destructor가 중요한지와, 값 복사 과정에서 object slicing이 어떻게 생기는지 정리합니다.

마지막 수정 2026년 3월 22일

기본 패턴

cpp
class Animal {
public:
    virtual ~Animal() = default;
    virtual void speak() const = 0;
};

class Dog : public Animal {
public:
    void speak() const override { std::cout << "woof\n"; }
};

설명

  • C++에서 다형성을 제대로 쓰려면 "기반 클래스 포인터나 참조로 파생 객체를 다룬다"는 전제가 깔립니다. 이때 소멸자까지 다형적으로 동작해야 자원 정리가 안전합니다.
  • 그래서 기반 클래스를 다형적으로 사용할 계획이라면 보통 virtual ~Base() = default;를 함께 둡니다. 그래야 Base*delete해도 실제 파생 클래스 소멸자가 호출됩니다.
  • object slicing은 파생 객체를 기반 클래스 "값"으로 복사할 때 파생 부분이 잘려 나가는 현상입니다. 즉 다형성을 기대했는데 값 복사 때문에 기반 부분만 남아 버리는 문제입니다.
  • 이 주제의 핵심은 "다형성은 값이 아니라 참조/포인터로 유지된다"는 점입니다. 값 복사를 하면 타입 계층의 정보가 줄어들 수 있고, 그 순간 virtual dispatch도 기대와 다르게 보일 수 있습니다.
  • 대학 교재 수준에서는 상속 문법보다 이 메모리 모델을 이해하는 것이 더 중요합니다. 그래야 왜 컨테이너에 Base 값을 넣는 것과 std::unique_ptr<Base>를 넣는 것이 다르게 동작하는지도 자연스럽게 연결됩니다.

빠른 정리

개념의미
virtual destructor기반 클래스 포인터 삭제 시 파생 소멸자까지 호출
object slicing파생 객체를 기반 클래스 값으로 복사하며 정보 손실
안전한 다형성기반 클래스 참조/포인터 사용
흔한 실수Base 값을 복사해 다형성을 기대함

주의할 점

다형적으로 쓸 클래스를 값으로 전달하거나 컨테이너에 값으로 담으면 object slicing이 발생할 수 있습니다. 기반 타입으로 다형성을 유지하고 싶다면 참조, 포인터, 스마트 포인터를 먼저 떠올리는 편이 좋습니다.

참고 링크

2 sources