stackoverflow上有this question,它提倡Scott Meyers规则,如果该类中有虚函数,则只构造析构函数虚拟。
我在一家拥有大型框架的公司工作,如果您的课程未来可以扩展,那么在编码时不清楚。在那个时间点,也可能无法更改该类(因为它是已发布的包的一部分)。
现在想象以下场景:
class A {
public:
A();
virtual ~A();
virtual m();
};
class B : public A {
public:
B();
~B();
};
class C : public B {
public:
C();
virtual ~C();
virtual m();
};
所以我创建了class B
,到现在为止,它无法更改。
现在class C
已创建,并用作B
:
B * b = new C();
delete b;
会发生什么事情,C的析构函数永远不会被调用,对吧?
在此方案中: 类是否应始终具有虚拟析构函数?
答案 0 :(得分:9)
当基类具有虚析构函数时,从它继承的所有类都自动具有虚析构函数(因此在您的示例中 - B的析构函数是隐式的)
如果要扩展/继承类,它应该具有虚拟析构函数。
答案 1 :(得分:3)
正如@Konrad Grochowski的回答所述,B
的析构函数是虚拟的,因此行为定义明确。在您的示例中,将调用C::~C()
。来自C ++规范§12.4.8:
析构函数可以声明为虚拟(10.3)或纯虚拟(10.4);如果在程序中创建了该类或任何派生类的任何对象,则应该定义析构函数。如果类具有带虚拟析构函数的基类,则其析构函数(无论是用户还是隐式声明)都是虚拟的。
更相关的问题是,当你的框架基类实际上有一个非虚拟析构函数(我认为是你所驾驶的),并且你的用户派生它时会发生什么。例如:
// Your framework:
class A
{
public:
A();
~A(); // non-virtual
};
// User's class:
class B : public A
{
B();
virtual ~B(); // virtual
virtual void UserMethod();
};
正如此问题(Non virtual destructor in base class, but virtual destructor in derived class cause segmentation fault)中所讨论的,这可能会导致您的用户遇到问题。如果您不确定用户是否将从您的类派生,它应该有一个虚拟析构函数,否则可能会出现问题。
要使用非虚拟析构函数强制执行正确的行为,您可以禁止用户从类派生,在这种情况下,非虚拟析构函数可能是安全的,假设您在框架中正确使用该类。在C ++ 11中,您可以使用final
来禁止派生。在C ++ 03及更低版本中,您可以使用技巧here来禁止派生。
答案 2 :(得分:0)
Scott Meyers在他的着作" Effective C ++:55改进你的程序和设计的具体方法(第3版)"如果该类具有另一个虚函数,则应该声明析构函数virtual
。否则仅创建virtual destructor
v-table,这将导致一些额外的资源消耗。
✦Polymorphic base classes should declare virtual destructors. If a
class has any virtual functions, it should have a virtual destructor.
✦Classes not designed to be base classes or not designed to be used
polymorphically should not declare virtual destructors.