본문 바로가기
노 코드

C++에서 기본 클래스의 소멸자에 `virtual` 키워드를 붙이는 이유

by 소소한사각형 2024. 5. 28.
반응형

C++에서 기본 클래스의 소멸자에 virtual 키워드를 붙이는 이유는 상속받는 파생 클래스의 객체가 삭제될 때 올바르게 소멸되도록 보장하기 위해서입니다. 이를 이해하기 위해서는 C++의 다형성과 소멸자 호출 메커니즘을 이해해야 합니다.

가상 소멸자의 필요성

만약 기본 클래스의 소멸자가 가상 함수가 아니면, 기본 클래스의 포인터로 파생 클래스 객체를 삭제할 때, 파생 클래스의 소멸자가 호출되지 않고 기본 클래스의 소멸자만 호출됩니다. 이는 메모리 누수나 다른 자원 해제가 제대로 이루어지지 않는 문제를 초래할 수 있습니다.

예제

가상 소멸자를 사용하지 않는 경우

#include <iostream>

class Base {
public:
    Base() { std::cout << "Base constructor\n"; }
    ~Base() { std::cout << "Base destructor\n"; }
};

class Derived : public Base {
public:
    Derived() { std::cout << "Derived constructor\n"; }
    ~Derived() { std::cout << "Derived destructor\n"; }
};

int main() {
    Base* obj = new Derived();
    delete obj; // Base destructor만 호출됩니다.
    return 0;
}

출력:

Base constructor
Derived constructor
Base destructor

위의 경우, delete objBase의 소멸자만 호출합니다. Derived의 소멸자는 호출되지 않아서, Derived 클래스가 소유한 리소스가 올바르게 해제되지 않습니다.

가상 소멸자를 사용하는 경우

#include <iostream>

class Base {
public:
    Base() { std::cout << "Base constructor\n"; }
    virtual ~Base() { std::cout << "Base destructor\n"; }
};

class Derived : public Base {
public:
    Derived() { std::cout << "Derived constructor\n"; }
    ~Derived() { std::cout << "Derived destructor\n"; }
};

int main() {
    Base* obj = new Derived();
    delete obj; // Base destructor와 Derived destructor가 모두 호출됩니다.
    return 0;
}

출력:

Base constructor
Derived constructor
Derived destructor
Base destructor

이 경우, delete objDerived의 소멸자와 Base의 소멸자를 모두 호출합니다. 따라서 파생 클래스 객체가 올바르게 소멸되고, 메모리 누수와 리소스 해제 문제가 해결됩니다.

정리

기본 클래스의 소멸자를 가상 함수로 선언함으로써, 파생 클래스의 객체가 기본 클래스 포인터를 통해 삭제될 때 올바르게 소멸되도록 할 수 있습니다. 따라서 기본 클래스에서 소멸자를 가상 함수로 선언하는 것은 상속 계층에서 안전하게 객체를 삭제하는 데 필수적입니다.

게임 인벤토리 예제에서 Item 클래스의 소멸자에 virtual을 붙이는 이유도 같은 맥락입니다. 이를 통해 Item 클래스를 상속받는 모든 파생 클래스의 객체가 올바르게 소멸될 수 있도록 보장할 수 있습니다.

class Item {
public:
    Item(const std::string& name, int weight) : name(name), weight(weight) {}
    virtual ~Item() {} // 가상 소멸자

    std::string getName() const { return name; }
    int getWeight() const { return weight; }
    virtual void use() const = 0; // 순수 가상 함수

protected:
    std::string name;
    int weight;
};

이렇게 하면 Item 클래스를 상속받는 Weapon, Armor, Potion 등의 객체가 삭제될 때 올바르게 소멸됩니다.

반응형