假设我有这段代码
class Base{
public:
int getVal();
private:
int a, b;
};
class Derived::public Base{
public:
void printVal();
};
int main(){
Base *b = new Derived();
delete b;
}
我知道虚拟析构函数会正确删除内容,但是如果没有虚函数并且派生类中没有数据成员,那么使用基指针(没有虚拟析构函数)删除是不是很糟糕?如果这样做会发生什么?
答案 0 :(得分:9)
使用基指针删除(没有虚拟析构函数)是不是很糟糕,即使派生类中没有虚函数也没有数据成员?
是
无论派生类的内容如何,行为都是未定义的。
如果这样做会怎样?
任何事情都可能发生。
答案 1 :(得分:7)
对于原始类型数据,您的示例很可能在实践中有效。事实上,产生vtable实际上可能阻碍性能(因此这里可能有一些合法用途),但 技术上未定义,根据5.3-5.4:< / p>
如果操作数的静态类型[ 删除操作符]不同于 它的动态类型,静态类型 应该是操作数的基类 动态类型和静态类型 有一个虚拟的析构函数或者 行为未定义。
这实际上取决于你班级数据的“堆积度”,并且因为没有堆分配的成员(在你的情况下),你应该没问题,但这肯定是代码味道。
答案 2 :(得分: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!
}