它说如果有一个虚函数,那么拥有一个虚拟析构函数是一个好习惯。但是,如果对象是在堆栈上创建的,而不是在堆上创建的,那么我们还需要这样做吗?
此致
答案 0 :(得分:9)
严格地说不 - 只有在通过引用基础对象的指针销毁对象时才需要虚拟析构函数。
如果破坏时的静态类型是对象的实际类型,那么无论它是否是虚拟的,都将调用正确的dtor。
但是如果一个类具有虚函数,那么其原因通常是可以通过指针或对其中一个对象库的引用来访问它。如果要通过该机制销毁对象,则使用虚拟dtor将确保调用正确的对象。如果你有一个虚拟功能,那么dtor虚拟就可以免费使用。
答案 1 :(得分:7)
是的,因为其他人可以编写在堆上创建对象的新代码。你的班级认为总是要在堆栈上创建它是不好的做法......
答案 2 :(得分:2)
如果使用虚方法编写对象,则需要通过接口/基础对象使用它。
预期你将通过指针(或智能指针)拥有此对象。在最后一种情况下,您需要虚拟析构函数。
在大多数情况下,你的代码会被其他人使用,你无法预测他们不会通过它的基指针使用该对象......事实上,有一天,你可能会这样使用它,太...
现在,在您的情况下,您的对象是在堆栈上创建的,这意味着编译器静态地知道它的类型。因此,当对象被销毁时,将直接调用正确的析构函数,从而导致零开销。
结论:正如你所说,这是一个简单的好习惯,考虑到大多数情况下虚拟析构函数的有限(或零)成本,应该坚持。
答案 3 :(得分:2)
简单规则:
为每个具有虚拟方法的类提供公共虚拟析构函数或受保护的非虚拟析构函数。
如果要通过指向基类的指针删除类的实例,则析构函数必须是虚拟的。如果您的类不打算通过基本指针删除,那么使析构函数保护将阻止外部代码通过基指针删除。
请注意,您可以使用多态行为而不通过基本指针删除:当您通过引用或指针传递对象但生命周期始终在最派生类型处理时,或使用shared_ptr
之类的结构时:
class base {
protected:
~base() {}
virtual void f();
};
class derived : public base {
public:
void f();
};
int main()
{
shared_ptr<base> sp( new derived );
base *b = new derived;
//delete b; // compile time error: cannot access ~base
// if it was allowed it would be UB
delete static_cast<derived*>(b); // correct (static_cast is ok, we know the type)
} // sp goes out of scope: delete at ´derived´ level
答案 4 :(得分:1)
OOP的目标之一是代码重用。因此,虽然您目前可能在堆栈上分配对象,但在重复使用和维护或团队开发环境中可能并非总是如此。
这通常是一个微不足道的开销,可以显着提高代码的实用性,可重用性和安全性。