如果基类析构函数是虚拟的,是否需要派生类析构函数定义

Is a derived class destructor definition required if base class destructor is virtual?

本文关键字:析构函数 派生 定义 是否 基类 虚拟 如果      更新时间:2023-10-16

我正在尝试以下示例:

class base // base class
{
public:
    std::list<base*> values;
    base(){}
    void initialize(base *b) {
        values.push_front(b);
    }
    virtual ~base()
    {
        values.clear();
        cout<<"base called"<<endl;
    }
};
class derived : public base // derived class
{
public:
    ~derived(){
        cout<<"derived called"<<endl;
    }
};
int main()
{
    derived *d = new derived;
    base *b = new base;
    b->initialize(static_cast<base *>(d)); /* filling list */
    delete b;
    return 0;
}

Q.1)为什么没有调用派生类的析构函数,就像我在values.clear()执行的基类析构函数一样?

Q.2) 如果基类析构函数是虚拟的,是否需要派生类析构函数定义?

Q1。因为您没有删除类型为 derived 的对象。您只执行 delete b; ,这会删除base。您还应该致电delete d;

此外,还应指定负责内存管理的对象。您的设计容易出错。您最好使用智能指针来防止歧义。此外,为了按预期运行,析构函数应为:

virtual ~base()
{
    for ( int i = 0 ; i < values.size() ; i++ )
        delete values[i];
    values.clear();
    cout<<"base called"<<endl;
}

当然,使用这种方法,在main中调用delete d;将是未定义的行为。

问题 2.不,定义不是必需的。

为什么没有调用派生类的析构函数,就像我在基类析构函数中执行的那样values.clear();

values.clear() 从此列表中删除所有指针。它不会删除指向的对象;这将是非常危险的,因为该列表无法知道它是否对它们的生命周期负责,或者它们是否只是用来引用在其他地方管理的对象。

如果您希望列表拥有对象,则必须在删除对象时自行删除它们,或者存储智能指针,例如 std::unique_ptr<base> 。如果您的编译器不支持新的智能指针,那么您可能会发现 Boost 的指针容器库很有用。

是否需要派生类析构函数定义。如果基类析构函数是虚拟的。

仅当派生类中存在需要清理的内容时,才需要它。如果它无事可做,则无需定义一个空的。

你实际上并没有delete d,所以当然不会调用析构函数。要么使d静态分配(derived d而不是derived *d = new derived),要么调用delete d

如果未在派生类中声明析构函数,则将创建默认析构函数。仍会调用基类析构函数,请参阅常见问题解答 (11.12)。另请注意,由于基类析构函数是虚拟的,因此派生类析构函数会自动成为虚拟的(无论是否定义),请参阅常见问题解答 (20.7)。

为什么你认为应该调用派生类的析构函数?您只删除基,它是基类的实例。

不,析构函数的定义不是必需的 - 您可以省略它。