10

下面的这个例子说明了如何防止派生类被复制。它基于声明了复制构造函数和复制赋值运算符的基类private

class Uncopyable
{
protected:
   // allow construction and destruction of derived objects...
   Uncopyable() {}
   ~Uncopyable() {}

private:
   // but prevent copying...
   Uncopyable(const Uncopyable&);
   Uncopyable& operator=(const Uncopyable&);
};

我们可以使用这个类,结合私有继承,使类不可复制:

class derived: private Uncopyable
{...};

请注意,类中的析构函数Uncopyable未声明为virtual.

以前,我了解到

  • 基类中的析构函数应该是virtual.
  • 不应该在非基类中使用析构函数virtual

在这个例子中,析构函数Uncopyableis not virtual,但它被继承自。这似乎与我之前学到的智慧背道而驰。

何时以及为什么不应将基类中的析构函数定义为virtual

4

5 回答 5

12

virtual仅当您可能尝试通过基类型的指针释放派生类型的对象时,才需要使用基类析构函数。因此,如果您只从基类private 继承而不是public,就像在 中的情况一样,那么您不必担心放入析构函数,因为在使用私有继承时,您无法获得指向派生对象并将其存储在指向基类型的指针中。Uncopyablevirtual

另一个示例可能是,如果您要使用像这样的 mixin 类,它使类跟踪对象分配的数量,其中 mixin 是从其中继承以获取行为但不被多态处理:

template <typename T> class Counter {
public:
    Counter() { ++numInstances; }
    Counter(const Counter&) { ++numInstances );
    ~Counter() { --numInstances; }

    static unsigned getNumInstances() { return numInstances; }

private:
    static unsigned numInstances;
}
template <typename T> unsigned Counter<T>::numInstances = 0;

更一般地,当使用静态多态性时,您不需要虚拟析构函数,因为您从不使用指向基类型的指针多态地处理类。您只使用指向派生类型的指针。

可能还有一些其他情况我没有在这里介绍,但是这两个(私有继承、mixin 类和静态多态性)涵盖了不需要虚拟析构函数的大部分空间。

于 2011-08-10T02:04:16.800 回答
2

当您将基础设计为不是接口时,而是作为实现细节(注意private继承自Uncopyable)。

于 2011-08-10T02:04:23.350 回答
1

如果您知道没有人会将它作为 Uncopyable* 删除,但始终将其作为相同的子类删除,则从技术上讲,您不必将 decostructor 设为虚拟。

是的,这基本上就是@templatetypedef 所说的,但我将以一种可能更简单的方式来解释它。

所以:如果人们可能会做这样的事情:

void aFunction(Uncopyable* obj) {
    delete obj;
}

然后你应该将你的析构函数声明为虚拟的(以确保潜在的子类调用它们的析构函数。

但是,如果您知道人们会像这样删除子类:

class Widget : public Uncopyable
{
  ....
};

void aFunction(Widget* obj) {
   delete obj;
}

然后,您不必将析构函数设为虚拟(因为将调用子类析构函数)。

至少,这是我的理解。

于 2011-08-10T02:05:33.477 回答
0

一般规则是使您的析构函数公开和虚拟,或受保护和非虚拟。在第一种情况下,您的对象以多态方式使用可破坏的,并且虚拟析构函数将做正确的事情。在第二种情况下,它只会作为实际的子类被销毁,并且仍然做正确的事情。

于 2011-08-10T02:56:24.553 回答
0

当你需要你的对象是普通的旧数据时,没有 vtable。如果我需要它,我会评论它,因为 99% 的时间在基类析构函数中省略“虚拟”只是一个错误,有人想要纠正它。

于 2011-08-10T02:04:01.773 回答