Answers:
对于界面而言,它甚至更为重要。该类的任何用户都可能持有指向该接口的指针,而不是指向具体实现的指针。当他们删除它时,如果析构函数不是虚拟的,他们将调用接口的析构函数(如果未指定,则调用编译器提供的默认值),而不是派生类的析构函数。即时内存泄漏。
例如
class Interface
{
virtual void doSomething() = 0;
};
class Derived : public Interface
{
Derived();
~Derived()
{
// Do some important cleanup...
}
};
void myFunc(void)
{
Interface* p = new Derived();
// The behaviour of the next line is undefined. It probably
// calls Interface::~Interface, not Derived::~Derived
delete p;
}
[expr.delete]/
:... if the static type of the object to be deleted is different from its dynamic type, ... the static type shall have a virtual destructor or the behavior is undefined. ...
。如果Derived使用隐式生成的析构函数,则仍将是不确定的。
您问题的答案通常是但并非总是如此。如果您的抽象类禁止客户调用指向它的指针的delete(或者在其文档中如此说),则可以自由地声明一个虚拟析构函数。
您可以通过保护其析构函数来禁止客户端在指向它的指针上调用delete。像这样工作,省略虚拟析构函数是完全安全和合理的。
最终,您最终将没有虚拟方法表,最终会向您的客户端发信号,表明您打算通过指向它的指针将其设为不可删除,因此您确实有理由在这种情况下不将其声明为虚拟。
[请参阅本文的项目4:http://www.gotw.ca/publications/mill18.htm ]
我决定进行一些研究,并尝试总结您的答案。以下问题将帮助您确定所需的析构函数:
我希望这有帮助。
*需要特别注意的是,C ++中没有办法将一个类标记为最终类(即不可子类化),因此,在您决定声明析构函数为非虚拟且公开的析构函数的情况下,切记要明确警告其他程序员不要来自你的班级。
参考文献:
是的,它总是很重要。派生类可以分配内存或保留对销毁对象时需要清除的其他资源的引用。如果不为接口/抽象类提供虚拟析构函数,则每次通过基类句柄删除派生类实例时,都不会调用派生类的析构函数。
因此,您正在释放潜在的内存泄漏
class IFoo
{
public:
virtual void DoFoo() = 0;
};
class Bar : public IFoo
{
char* dooby = NULL;
public:
virtual void DoFoo() { dooby = new char[10]; }
void ~Bar() { delete [] dooby; }
};
IFoo* baz = new Bar();
baz->DoFoo();
delete baz; // memory leak - dooby isn't deleted
它并不总是必需的,但我认为这是一种很好的做法。它的作用是允许派生对象通过基本类型的指针安全地删除。
因此,例如:
Base *p = new Derived;
// use p as you see fit
delete p;
如果Base
没有虚拟析构函数,则格式错误,因为它将尝试删除对象,就好像它是一个Base *
。
shared_ptr
它将尝试删除对象,就好像它是一个对象一样Base *
-它会记住创建对象的类型。请参阅引用的链接,特别是写着“析构函数将使用相同的指针调用delete的指针,并使用其原始类型完成,即使T没有虚拟析构函数或为空也是如此。”
这不仅是一种好习惯。这是任何类层次结构的规则#1。
现在,为什么。采取典型的动物等级制度。与其他任何方法调用一样,虚拟析构函数也要进行虚拟调度。请看下面的例子。
Animal* pAnimal = GetAnimal();
delete pAnimal;
假设Animal是一个抽象类。C ++知道正确的析构函数调用的唯一方法是通过虚拟方法分派。如果析构函数不是虚拟的,则它将仅调用Animal的析构函数,而不销毁派生类中的任何对象。
使析构函数在基类中虚拟化的原因是,它只是从派生类中删除了选择。默认情况下,它们的析构函数变为虚拟的。
delete p
调用未定义的行为。不能保证致电Interface::~Interface
。