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

时间:2012-04-23 10:55:16

标签: c++ virtual-destructor

我正在尝试以下示例:

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)如果基类析构函数是虚拟的,是否需要派生类析构函数定义?

4 个答案:

答案 0 :(得分:7)

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;
}

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

Q2。不,这个定义不是必需的。

答案 1 :(得分:4)

  

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

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

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

  

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

只有在派生类中有需要清理的东西时才需要它。如果没有什么可以做的话,就没有必要定义一个空的。

答案 2 :(得分:1)

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

如果未在派生类中声明析构函数,则将创建默认析构函数。仍将调用基类析构函数,请参阅FAQ(11.12)。另请注意,由于基类析构函数是虚拟的,派生类析构函数是自动虚拟的(无论您是否定义),请参阅FAQ(20.7)。

答案 3 :(得分:0)

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

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