【问题标题】:C++ is Virtual destructor still needed if there are no data members in derived?如果派生中没有数据成员,C ++是否仍然需要虚拟析构函数?
【发布时间】:2011-04-26 01:55:18
【问题描述】:

假设我有这个代码

class Base{
  public:
        int getVal();
  private:
         int a, b;
};

class Derived::public Base{
    public:
         void printVal();
};

int main(){
    Base *b = new Derived();
    delete b;    
}

我知道虚拟析构函数可以正确删除内容,但是即使派生类中没有虚拟函数且没有数据成员,使用基指针删除(当没有虚拟析构函数时)是否不好?如果这样做会发生什么?

【问题讨论】:

    标签: c++ virtual-destructor


    【解决方案1】:

    即使派生类中没有虚函数也没有数据成员,用基指针删除(当没有虚析构函数时)是不是很糟糕?

    是的。

    无论派生类的内容如何,​​行为都是未定义的。

    如果这样做会发生什么?

    任何事情都可能发生。

    【讨论】:

    • +1 表示“任何事情都可能发生”。任何事物!绝对什么! :)
    【解决方案2】:

    对于原始类型数据,您的示例很可能在实践中有效。事实上,产生一个 vtable 实际上可能阻碍性能(因此这里可能有一些合法的用途),但它在技术上是未定义的,根据 5.3-5.4:

    如果操作数的静态类型[的 删除运算符] 不同于 它的动态类型,静态类型 应该是操作数的基类 动态类型和静态类型应 有一个虚拟析构函数或 行为未定义。

    这真的完全取决于你类中数据的“堆”,并且由于没有堆分配的成员(在你的情况下),你应该没问题,但这绝对是代码味道。

    【讨论】:

    • 依赖那些“最有可能奏效”的东西并假设你“应该没问题”是很危险的。编写工作的代码要好得多,然后你知道你会没事的。
    • James,我会确保始终有一个虚拟析构函数。这只是某人提出的假设,并没有答案。再次感谢你们。
    • @James,我实际上认为这 可能 每次都可以使用原语(只是因为 C++ 中对象是如何分配/释放的),并且该子句被添加为一般性,因为通常情况下,一些成员将被分配到堆中。
    • 如果后来有人从 Derived 派生了一个新类,并且该类确实有需要销毁的成员,那么这也是值得考虑的。如果你的基类没有虚拟析构函数,那么新类就不能安全地多态使用。
    • “技术上未定义”与“未定义”有何不同?
    【解决方案3】:

    当通过指向基类的指针创建派生对象时,需要派生类中的虚拟析构函数才能正确调用派生析构函数(多态性)。

    高完整性 CPP 规则 3.3.2 为基类编写一个“虚拟”析构函数。 (QACPP 2116)

    理由:如果一个对象将通过指向其基类的指针被销毁,那么该基类应该有一个虚拟析构函数。如果基类析构函数不是虚拟的,则只会调用基类的析构函数。在大多数情况下,析构函数应该是虚拟的,因为维护或重用可能会添加需要虚拟析构函数的派生类。

    class Base {}; 
    class Derived : public Base { public: ~Derived() {} }; 
    
    void foo() {  
       Derived* d = new Derived; delete d; // correctly calls derived destructor 
    } 
    void boo() { 
       Derived* d = new Derived; Base* b = d; delete b; // problem! does not call derived destructor! 
    }
    

    【讨论】:

    • @Mike Ellery,是的,这就是我想要的意思。我已经更正了代码。
    猜你喜欢
    • 2019-10-11
    • 2014-03-23
    • 2021-08-22
    • 2021-03-20
    • 1970-01-01
    • 2020-10-29
    • 2012-04-18
    • 1970-01-01
    • 2011-11-16
    相关资源
    最近更新 更多