当一个类是更大框架的一部分时,析构函数应该总是虚拟的吗?

时间:2015-05-22 08:37:36

标签: c++

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的析构函数永远不会被调用,对吧?

在此方案中: 类是否应始终具有虚拟析构函数

3 个答案:

答案 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.