C++ 具有非虚析构函数的派生类

C++ 具有非虚析构函数的派生类,c++,C++,在任何情况下,派生类具有非虚拟析构函数都是合法的吗?非虚析构函数表示不应将类用作基类。派生类的非virtual析构函数是否会像Javafinal修饰符的弱形式 我特别感兴趣的是派生类的基类有一个虚拟的析构函数。是、否和否 虚拟析构函数和类作为基类或派生类的能力无关。这两者都是合法的 然而,使析构函数虚拟化有一定的原因。请参见此处:。这使得一个类,除其他外,如果它还没有一个虚拟表,就有一个虚拟表。但是,C++不需要虚拟表来继承。 在任何情况下,衍生产品是否合法 类是否具有非虚拟析构函数 对 非虚拟

在任何情况下,派生类具有非虚拟析构函数都是合法的吗?非虚析构函数表示不应将类用作基类。派生类的非virtual析构函数是否会像Java
final
修饰符的弱形式

我特别感兴趣的是派生类的基类有一个
虚拟的
析构函数。

是、否和否

虚拟析构函数和类作为基类或派生类的能力无关。这两者都是合法的

然而,使析构函数虚拟化有一定的原因。请参见此处:。这使得一个类,除其他外,如果它还没有一个虚拟表,就有一个虚拟表。但是,C++不需要虚拟表来继承。 在任何情况下,衍生产品是否合法 类是否具有非虚拟析构函数

非虚拟析构函数表示类不应用作 基类

不是真的;非虚拟析构函数表示通过
base
指针删除
derived
的实例将不起作用。例如:

class Base {};
class Derived : public Base {};

Base* b = new Derived;
delete b; // Does not call Derived's destructor!
如果您不按上述方式执行
删除
,则可以。但是如果是这样的话,那么您可能会使用组合而不是继承

拥有派生类的非虚拟析构函数会像 Java最终修饰符的弱形式


否,因为
virtual
-ness会传播到派生类

class Base
{
public:
    virtual ~Base() {}
    virtual void Foo() {};
};

class Derived : public Base
{
public:
    ~Derived() {}  // Will also be virtual
    void Foo() {}; // Will also be virtual
};
C++03或更早版本中没有内置的语言机制来防止子类(*)。这不是什么大问题,因为你应该一直这样。也就是说,当“是-a”关系比真正的“有-a”关系更有意义时,使用继承


(*)C++11中引入了“final”修饰符,只要在删除对象时不想将其用作派生类的基指针,非虚拟析构函数就完全可以了


如果您以多态方式访问它的派生类,用基指针传递并存储它,然后删除它,那么答案是否定的,请使用虚拟析构函数。

如果您永远不会对指向派生类对象的基类指针调用delete,则使用非虚拟析构函数的基类是完全有效的

指南#:仅当派生类需要调用虚拟函数的基本实现时,才保护虚拟函数。 仅针对析构函数的特殊情况:

指南#:基类析构函数应该是公共的和虚拟的,或者是受保护的和非虚拟的


也许你的问题实际上是:
如果基类析构函数是虚拟的,派生类中的析构函数是否需要是虚拟的

答案是否定的。

如果基类析构函数是虚拟的,那么派生类析构函数已经是隐式虚拟的,您不需要显式地将其指定为虚拟的。

取决于类的用途。有时,让析构函数受到保护是一种很好的做法,但不是虚拟的——这基本上是说:“您不应该通过基类型指针删除派生类的对象”

是的,有:

void dothis(Base const&);

void foo() {
  Derived d;
  tothis(d);
}
在这里,类是以多态方式使用的,但是没有调用
delete
,因此没有问题

另一个例子是:

std::shared_ptr<Base> create() { return std::shared_ptr<Base>(new Derived); }
std::shared_ptr create(){return std::shared_ptr(新派生);}
因为
shared_ptr
能够使用非多态的
delete
(通过类型擦除)


我在Clang中实现了一个警告,专门用于检测对具有非虚拟析构函数的多态非final类的
delete
调用,因此如果使用
Clang-Wdelete非虚拟dtor
,它将专门针对这种情况发出警告。

如果派生类没有向基类添加任何数据成员,并且有一个空的析构函数体,那么析构函数是否是虚拟的就无关紧要了——派生析构函数所要做的就是调用基析构函数。不建议这样做,因为在没有意识到这些限制的情况下修改类对某人来说太容易了

如果您从未尝试通过指向基类的指针删除对象,那么您将是安全的。这是另一个很难执行的规则,应该谨慎使用

有时您对基类没有任何控制权,并且被迫从基类派生,即使析构函数不是虚拟的


最后,在基类中使用非虚拟析构函数不会对将由编译器强制执行的派生类施加任何限制,因此我认为它与Java的final一点也不相似。

您的问题并不清楚。如果基类具有虚拟 无论如何,派生类将有一个析构函数。不可能 在声明虚拟性后关闭虚拟性

当然,在某些情况下,从 类,该类没有虚拟析构函数。基地的原因是什么 类析构函数应该是虚拟的,这样您就可以通过 指向基类的指针。如果派生是私有的,则没有 要担心这一点,因为您的
派生*
不会转换为
基*
。 否则,我看到的建议是,如果基类 析构函数不是虚拟的,应该加以保护;这就阻止了 未定义行为(通过指向基的指针删除)的情况 可能发生。然而,在实践中,许多基类(例如。
std::iterator
)的语义使得它甚至不会出现在 任何人都可以创建指向它们的指针;更不用说通过这种方式删除了 指针。因此,添加保护可能比w更费力
struct base {
   virtual ~base() {}       // destructor is virtual
};
struct derived : base {
   ~derived() {}            // destructor is also virtual, because it is virtual in base
};
class Base{
public:
    //No virtual destructor defined
    virtual void Foo() {};
};

class Derived final : public Base{
public:
    ~Derived() {}  // define some non-virtual destructor
    void Foo() {}; // Will also be virtual
};
class Base{
public:
  //No virtual destructor defined
  virtual void Foo() = 0; // abstract method
};
class Derived final : public Base{
public:
  ~Derived() {}  // define some non-virtual destructor
  void Foo() {}; // Will also be virtual
};