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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7403883/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 16:53:16  来源:igfitidea点击:

Derived class with non-virtual destructor

c++

提问by Raedwald

Are there any circumstances in which it is legitimate for a derived class to have a non-virtualdestructor? A non-virtualdestructor signifies that a class should not be used as a base-class. Will having a non-virtualdestructor of a derived class act like a weak form of the Java finalmodifier?

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

I am especially interested in the case where the base class of the derived class has a virtualdestructor.

我对派生类的基类有virtual析构函数的情况特别感兴趣。

回答by In silico

Are there any circumstances in which it is legitimate for a derived class to have a non-virtual destructor?

在任何情况下,派生类具有非虚拟析构函数是合法的吗?

Yes.

是的。

A non-virtual destructor signifies that a class should not be used as a base-class.

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

Not really; a non-virtual destructor signifies that deleting an instance of derivedvia a basepointer will not work. For example:

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

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

Base* b = new Derived;
delete b; // Does not call Derived's destructor!

If you don't do deletein the above manner, then it will be fine. But if that's the case, then you would probably be using composition and not inheritance.

如果你不delete按照上面的方式去做,那就没问题了。但如果是这种情况,那么您可能会使用组合而不是继承。

Will having a non-virtual destructor of a derived class act like a weak form of the Java final modifier?

派生类的非虚拟析构函数是否会像 Java final 修饰符的弱形式一样?

No, because virtual-ness propagates to derived classes.

不,因为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
};

There isn't a built-in language mechanism in C++03 or earlier to prevent subclasses(*). Which isn't much of an issue anyway since you should always prefer composition over inheritance. That is, use inheritance when a "is-a" relationship makes more sense than a true "has-a" relationship.

C++03 或更早版本中没有内置语言机制来防止子类(*)。无论如何,这不是什么大问题,因为您应该始终更喜欢组合而不是继承。也就是说,当“is-a”关系比真正的“has-a”关系更有意义时,使用继承。

(*) 'final' modifier was introduced in C++11

(*) C++11 中引入了“final”修饰符

回答by Alok Save

It is perfectly valid to have an Base class with an non virtual destructor if you are never going to call delete on a Base class pointer pointing to an derived class object.

如果您永远不会在指向派生类对象的基类指针上调用 delete,那么拥有一个带有非虚拟析构函数的基类是完全有效的。

Follow Herb Sutter's Advice:

遵循 Herb Sutter 的建议

Guideline #:Only if derived classes need to invoke the base implementation of a virtual function, make the virtual function protected. For the special case of the destructor only:

准则#:仅当派生类需要调用虚函数的基实现时,才使虚函数受保护。仅对于析构函数的特殊情况:

Guideline #:A base class destructor should be either public and virtual, or protected and nonvirtual.

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



Maybe your question actually is:
Does Destructor in Derivedclass needs to be virtual if Base class Destructor is virtual?

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

The answer is NO.
If Base class destructor is virtual then the Derived class destructor is implicitly virtual already, you don't need to specify it as virtual explicitly.

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

回答by David Rodríguez - dribeas

Addresssing the latest edit:

解决最新的编辑:

Edit: I am especially interested in the case where the base class of the derived class has a virtual destructor.

编辑:我对派生类的基类具有虚拟析构函数的情况特别感兴趣。

In that case, the destructor of the derived class willbe virtual, regardless of whether you add the virtualkeyword or not:

在这种情况下,派生类的析构函数是虚拟的,无论您是否添加virtual关键字:

struct base {
   virtual ~base() {}       // destructor is virtual
};
struct derived : base {
   ~derived() {}            // destructor is also virtual, because it is virtual in base
};

This is not limited to destructors, if at any point in a type hierarchy a function member is declared virtual, all overrides (not overloads) of that same function will be virtual, whether they are declared as so or not. The specific bit for destructors is that ~derived()overridesvirtual ~base()even if the nameof the member differs --that is the only specificity for destructors here.

这不仅限于析构函数,如果在类型层次结构中的任何一点将函数成员声明为虚函数,则该函数的所有覆盖(不是重载)都将是虚函数,无论它们是否声明为虚函数。析构函数的特定位是即使成员的名称不同也会~derived()覆盖——这是这里析构函数的唯一特殊性。virtual ~base()

回答by James Kanze

You're question isn't really clear. If the base class has a virtual destructor, the derived class will have one, regardless. There's no way to turn virtuality off, once it's been declared.

你的问题不是很清楚。如果基类有一个虚拟析构函数,派生类将有一个,无论如何。一旦宣布,就无法关闭虚拟性。

And there are certainly cases where it makes sense to derive from a class which doesn't have a virtual destructor. The reason why the base class destructor should be virtual is so that you can delete through a pointer to the base class. If the derivation is private, you don't have to worry about this, since your Derived*won't convert to a Base*. Otherwise, I've seen the recommendation that if the base class destructor isn't virtual, it should be protected; this prevents the one case of undefined behavior (deleting through a pointer to base) that could occur. In practice, however, a lot of base classes (e.g. std::iterator<>) have semantics such that it doesn't even occur to anyone to create pointers to them; much less delete through such pointers. So adding the protection may be more effort than it's worth.

并且在某些情况下,从没有虚拟析构函数的类派生是有意义的。基类析构函数之所以应该是虚拟的,是为了可以通过指向基类的指针进行删除。如果派生是私有的,您不必担心这一点,因为您Derived*不会转换为Base*. 否则,我已经看到了这样的建议:如果基类析构函数不是虚拟的,则应该对其进行保护;这可以防止可能发生的一种未定义行为(通过指向 base 的指针删除)。然而,在实践中,许多基类(例如 std::iterator<>)具有语义,以至于任何人都不会想到创建指向它们的指针;更不用说通过这样的指针删除了。所以增加保护可能比它更努力'

回答by Nemanja Trifunovic

Depends on the purpose of your class. Sometimes it is a good practice to make your destructor protected, but not virtual - that basically says: "You shall not delete an object of derived class via a base-type pointer"

取决于你上课的目的。有时使析构函数受保护而不是虚拟是一种很好的做法 - 这基本上是说:“您不应通过基类型指针删除派生类的对象”

回答by Mark Ransom

If your derived class doesn't add any data members to the base class, and has an empty destructor body, then it won't matter if the destructor is virtual or not - all the derived destructor will do is call the base one anyway. It isn't recommended because it's far too easy for someone to come along and modify the class without being aware of these restrictions.

如果您的派生类没有向基类添加任何数据成员,并且有一个空的析构函数体,那么析构函数是否是虚拟的都无关紧要 - 派生析构函数所做的只是调用基类。不推荐这样做,因为有人很容易在没有意识到这些限制的情况下修改类。

If you never try to delete an object through a pointer to the base class, you'll be safe. This is another rule that's hard to enforce and should be used with care.

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

Sometimes you don't have any control over the base class and you're forced to derive from it, even though the destructor isn't virtual.

有时,即使析构函数不是虚拟的,您也无法控制基类,并且被迫从中派生。

Finally, having a non-virtual destructor in the base class doesn't impose any restriction on the derived class that will be enforced by the compiler, so I don't think it resembles Java's final at all.

最后,在基类中有一个非虚拟析构函数不会对编译器强制执行的派生类施加任何限制,所以我认为它根本不像 Java 的 final。

回答by Matthieu M.

Yes, there are:

是的,有:

void dothis(Base const&);

void foo() {
  Derived d;
  tothis(d);
}

Here the class is used polymorphically, yet deleteis not called, thus it's fine.

这里的类是多态使用的,但delete没有被调用,因此很好。

Another example would be:

另一个例子是:

std::shared_ptr<Base> create() { return std::shared_ptr<Base>(new Derived); }

because a shared_ptris able to use a non-polymorphic delete(through type erasure).

因为 ashared_ptr能够使用非多态delete(通过类型擦除)。

I implemented a warning in Clang specifically to detect the call of deleteon polymorphic non-final classes with non-virtual destructors, so if you use clang -Wdelete-non-virtual-dtor, it will warn specifically for this case.

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

回答by Karoly Horvath

A non-virtual destructor is perfectly fine as long as you you don't want to use it as a base pointer for derived classes when deleting the object.

只要您不想在删除对象时将其用作派生类的基指针,非虚拟析构函数就完全没问题。

If you its derived classes in a polymorphic way, passing and storing it with a base pointer and then deleting it then the answer is no, use a virtual destructor.

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

回答by Pavel Radzivilovsky

Yes, No and No.

是的,不和不。

Virtual destructor has nothing to do with ability of the class to be a base or a derived class. It is a legitimate one as both.

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

However, there are certain reasons to make destructors virtual. See here: http://en.wikipedia.org/wiki/Virtual_destructor#Virtual_destructors. This makes a class, among other things, have a virtual table if it doesn't have one already. However, virtual tables are not required by C++ to do inheritance.

但是,有某些原因可以使析构函数成为虚拟的。请参阅此处:http: //en.wikipedia.org/wiki/Virtual_destructor#Virtual_destructors。这使得一个类有一个虚拟表,如果它还没有的话。但是,C++ 不需要虚拟表来进行继承。

回答by SRF

Will having a non-virtual destructor of a derived class act like a weak form of the Java final modifier?

派生类的非虚拟析构函数是否会像 Java final 修饰符的弱形式一样?

Not at all. Here is my suggestion to prevent sub classes in C++ (like final modifier in Java); make the destructor private in a class. Then you can prevent making sub-classes from it

一点也不。这是我的建议,以防止 C++ 中的子类(如 Java 中的 final 修饰符);使析构函数在类中私有。然后你可以防止从它创建子类