4

我正在尝试以下示例:

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

4 回答 4

7

Q1。因为您没有删除 type 的对象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。不,不需要定义。

于 2012-04-23T10:59:01.417 回答
4

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

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

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

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

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

于 2012-04-23T11:00:25.943 回答
1

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

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

于 2012-04-23T10:58:50.047 回答
0

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

不,不需要析构函数的定义——你可以省略它。

于 2012-04-23T11:00:00.427 回答