【问题标题】:Is it always necessary to declare destructor as virtual, if the class contains atleast a virtual function? [duplicate]是否总是需要将析构函数声明为虚拟的,该类至少包含一个虚拟函数? [复制]
【发布时间】:2012-02-24 02:34:57
【问题描述】:

可能重复:
When to use virtual destructors?

如果一个类(具有虚函数)及其继承类的所有数据成员都是非指针类型(意味着它不能保存任何动态内存),是否需要将析构函数声明为虚函数?

例子

class base {
    int x;
public:
    virtual void fn(){}

};

class der: public base {
    int y;
public:
    void fn(){}

};

这里我们需要一个虚拟析构函数吗?

【问题讨论】:

    标签: c++


    【解决方案1】:

    不,这不是必需的,并且始终这样做甚至会损害性能。

    除非您delete 一个基类指针实际存储派生类对象,否则您不会遇到 UB(未定义行为)。因此,是否需要虚拟析构函数取决于代码实际创建和释放对象的方式,而不仅仅取决于类。

    顺便说一句,派生类与基类相比是否需要任何额外的破坏并不重要——如果delete应用于存储派生类对象地址的基类指针无论如何都是UB,则缺少虚拟析构函数。

    【讨论】:

    • 关于性能:只要你内联析构函数体,这并不重要。
    • @Matthieu M.:通常使用 vtable 调用虚拟析构函数 - 此类调用未内联。
    • 影响性能?如何? vtable 的成本已经支付(问题中的假设是至少有一个其他虚拟功能)。现在,如果对象通过指向基的指针被销毁,这是一个要求,如果它们具有自动存储,则调用将被静态分派。只有当它们通过指向完整对象的指针是deleted 时,动态调度的成本才会受到影响,即使这样也可以忽略不计。这种关于性能的误导性 cmet 使新程序员做错误的事情来避免不存在的成本。
    • @sharptooth:实际上没有。如果满足两个条件,则使用 vtable 调用 virtual 析构函数:调用不明确应该使用哪种静态类型并且无法推断此静态类型。如果静态类型已知,则可以内联调用。这对于析构函数能够内联它们很重要,因为子类静态调用基类析构函数。
    • 注意:我假设 UB 表示未定义的行为,尽管我以前从未见过这样称呼它。
    【解决方案2】:

    不,它并不总是必要的。这只是一个经验法则,因此并不总是适用。

    真正的规则说:

    当要通过基类指针删除派生类的对象时,必须声明析构函数virtual

    否则,通过基类指针删除派生类对象会调用未定义的行为。 (最可能的结果是只调用了基类的析构函数。)

    当然,这条规则对于新手来说是相当多的,因此更简单的经验法则,几乎总是正确的。 非常您很可能正在通过多态类层次结构中的基类指针管理动态创建的派生类对象,并且您不太可能非常为非多态类层次结构。

    【讨论】:

      【解决方案3】:

      虚拟析构函数确保当您拥有指向基类的指针时调用继承的类析构函数。

      在这种特殊情况下,您不需要它,但用户可以从der 继承另一个类(让它成为foo),它使用例如动态内存分配。在这种情况下,除非他有一个 foo 类型的指针,否则不会调用析构函数。

      所以不,这不是“必要的”,但如果您已经至少有一个虚函数(因此您已经有一个 VTABLE),也没有什么坏处。如果您假设这些类将由用户继承并使用指向基类的指针释放,则这是强制性的。

      【讨论】:

        【解决方案4】:

        是的。

        任何时候你创建一个带有虚函数的类,你都需要将析构函数也声明为虚函数。

        考虑这种情况 -

        base *b = new der();
        delete b;
        

        由于您在基指针上进行操作,它不知道它实际上是子类的对象,因此永远不会调用 der 的析构函数。这可能会导致内存泄漏等问题。

        【讨论】:

        猜你喜欢
        • 2011-08-02
        • 2012-03-09
        • 2021-08-22
        • 2012-06-26
        • 2011-03-30
        • 2015-11-12
        • 2019-10-11
        • 1970-01-01
        • 2018-10-23
        相关资源
        最近更新 更多