12

假设我有这个代码

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

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

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

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

4

3 回答 3

9

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

是的。

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

如果这样做会发生什么?

什么事情都可能发生。

于 2010-10-15T18:01:54.823 回答
7

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

如果[删除运算符]操作数的静态类型与其动态类型不同,则静态类型应为操作数动态类型的基类,并且静态类型应具有虚拟析构函数或行为未定义。

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

于 2010-10-15T18:08:09.773 回答
2

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

高完整性 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! 
}
于 2010-10-15T19:15:24.643 回答