C++ 虚拟析构函数是继承的吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2198379/
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
Are virtual destructors inherited?
提问by cairol
If I have a base class with a virtual destructor. Has a derived class to declare a virtual destructor too?
如果我有一个带有虚拟析构函数的基类。是否有派生类也可以声明虚拟析构函数?
class base {
public:
virtual ~base () {}
};
class derived : base {
public:
virtual ~derived () {} // 1)
~derived () {} // 2)
};
Concrete questions:
具体问题:
- Is 1) and 2) the same? Is 2) automatically virtual because of its base or does it "stop" the virtualness?
- Can the derived destructor be omitted if it has nothing to do?
- What's the best practice for declaring the derived destructor? Declare it virtual, non-virtual or omit it if possible?
- 1) 和 2) 一样吗?2)是因为它的基础而自动虚拟还是它“停止”了虚拟性?
- 派生析构函数如果无关可以省略吗?
- 声明派生析构函数的最佳实践是什么?如果可能,将其声明为虚拟的、非虚拟的或省略它?
回答by Omnifarious
- Yes, they are the same. The derived class not declaring something virtual does not stop it from being virtual. There is, in fact, no way to stop any method (destructor included) from being virtual in a derived class if it was virtual in a base class. In >=C++11 you can use
final
to prevent it from being overridden in derived classes, but that doesn't prevent it from being virtual. - Yes, a destructor in a derived class can be omitted if it has nothing to do. And it doesn't matter whether or not its virtual.
- I would omit it if possible. And I always use the
virtual
keyword again for virtual functions in derived classes for reasons of clarity. People shouldn't have to go all the way up the inheritance hierarchy to figure out that a function is virtual. Additionally, if your class is copyable or movable without having to declare your own copy or move constructors, declaring a destructor of any kind (even if you define it asdefault
) will force you to declare the copy and move constructors and assignment operators if you want them as the compiler will no longer put them in for you.
- 是的,它们是一样的。派生类没有声明虚拟的东西并不会阻止它成为虚拟的。事实上,如果任何方法(包括析构函数)在派生类中是虚拟的,则无法阻止它在基类中是虚拟的。在 >=C++11 中,您可以使用
final
来防止它在派生类中被覆盖,但这并不能防止它成为虚拟的。 - 是的,派生类中的析构函数可以省略,如果它无关。并且它是否是虚拟的并不重要。
- 如果可能,我会省略它。
virtual
为了清楚起见,我总是再次将关键字用于派生类中的虚函数。人们不应该一直向上继承层次结构来确定函数是虚拟的。此外,如果您的类是可复制或可移动的,而无需声明您自己的复制或移动构造函数,则声明任何类型的析构函数(即使您将其定义为default
)将迫使您根据需要声明复制和移动构造函数以及赋值运算符它们,因为编译器将不再为您放入它们。
As a small point for item 3. It has been pointed out in comments that if a destructor is undeclared the compiler generates a default one (that is still virtual). And that default one is an inline function.
作为第 3 项的一个小点。在评论中已经指出,如果未声明析构函数,编译器会生成一个默认的(仍然是虚拟的)。而默认的是一个内联函数。
Inline functions potentially expose more of your program to changes in other parts of your program and make binary compatibility for shared libraries tricky. Also, the increased coupling can result in a lot of recompilation in the face of certain kinds of changes. For example, if you decide you really do want an implementation for your virtual destructor then every piece of code that called it will need to be recompiled. Whereas if you had declared it in the class body and then defined it empty in a .cpp
file you would be fine changing it without recompiling.
内联函数可能会将更多的程序暴露给程序其他部分的更改,并使共享库的二进制兼容性变得棘手。此外,面对某些类型的更改,增加的耦合可能会导致大量的重新编译。例如,如果你决定你真的想要一个虚拟析构函数的实现,那么调用它的每一段代码都需要重新编译。而如果您已在类主体中声明它,然后在.cpp
文件中将其定义为空,则无需重新编译就可以更改它。
My personal choice would still be to omit it when possible. In my opinion it clutters up the code, and the compiler can sometimes do slightly more efficient things with a default implementation over an empty one. But there are constraints you may be under that make that a poor choice.
我个人的选择仍然是尽可能省略它。在我看来,它使代码变得混乱,并且编译器有时可以使用默认实现而不是空实现来做更高效的事情。但是,您可能会受到一些限制,使之成为一个糟糕的选择。
回答by falstro
- The destructor is automatically virtual, as with all methods. You can't stop a method from being virtual in C++ (if it has already been declared virtual, that is, i.e. there's no equivalent of 'final' in Java)
- Yes it can be omitted.
- I would declare a virtual destructor if I intend for this class to be subclassed, no matter if it's subclassing another class or not, I also prefer to keep declaring methods virtual, even though it's not needed. This will keep subclasses working, should you ever decide to remove the inheritance. But I suppose this is just a matter of style.
- 与所有方法一样,析构函数是自动虚拟的。你不能阻止一个方法在 C++ 中是虚拟的(如果它已经被声明为虚拟的,也就是说,在 Java 中没有等价的 'final')
- 是的,可以省略。
- 如果我打算对这个类进行子类化,我会声明一个虚拟析构函数,无论它是否子类化另一个类,我也更喜欢继续声明方法为虚拟的,即使它不需要。如果您决定删除继承,这将使子类继续工作。但我想这只是风格问题。
回答by Klaim
A virtual member function will make implicitely any overloading of this function virtual.
虚拟成员函数将隐式地使该函数的任何重载成为虚拟的。
So the virtual in 1) is "optional", the base class destructor being virtual makes all child destructors virtual too.
所以 1) 中的虚拟是“可选的”,基类析构函数是虚拟的,也使所有子析构函数都是虚拟的。
回答by AProgrammer
1/ Yes 2/ Yes, it will be generated by the compiler 3/ The choice between declaring it virtual or not should follow your convention for overriden virtual members -- IMHO, there are good arguments both way, just choose one and follow it.
1/ 是的 2/ 是的,它将由编译器生成 3/ 是否将其声明为虚拟的选择应该遵循您对覆盖虚拟成员的约定——恕我直言,两种方式都有很好的论据,只需选择一个并遵循它。
I'd omit it if possible, but there is one thing which may incite you to declare it: if you use the compiler generated one, it is implicitly inline. There are time when you want to avoid inline members (dynamic libraries for instance).
如果可能,我会省略它,但是有一件事可能会促使您声明它:如果您使用编译器生成的一个,它是隐式内联的。有时您想避免内联成员(例如动态库)。
回答by Alex Maystrenko
Virtual functions are overridden implicitly. When the method of a child class matches the method signature of the virtual function from a base class, it is overridden.
This is easy to confuse and possibly break during refactoring, so there are override
and final
keywords since C++11 to mark this behavior explicitly. There is a corresponding warnings that forbid the silent behavior, for example -Wsuggest-override
in GCC.
虚函数被隐式覆盖。当子类的方法与基类中虚函数的方法签名匹配时,它会被覆盖。这在重构过程中很容易混淆并可能会中断,因此自 C++11 以来就有override
andfinal
关键字来显式标记此行为。有相应的警告禁止静默行为,例如-Wsuggest-override
在 GCC 中。
There is a related question for override
and final
keywords on SO: Is the 'override' keyword just a check for a overridden virtual method?.
SO 上有一个相关的问题override
和final
关键字:“覆盖”关键字是否只是检查被覆盖的虚拟方法?.
And the documentation in the cpp reference https://en.cppreference.com/w/cpp/language/override
以及 cpp 参考中的文档https://en.cppreference.com/w/cpp/language/override
Whether to use override
keyword with the destructors is still a bit of debate. For example see discussion in this related SO question: default override of virtual destructorThe issue is, that the semantics of the virtual destructor is different to normal functions. Destructors are chained, so all base classes destructors are called after child one. However, in case of a regular method base implementations of the overridden method are not called by default. They can be called manually when needed.
是否override
在析构函数中使用关键字仍然存在争议。例如,请参阅此相关 SO 问题中的讨论:虚拟析构函数的默认覆盖问题是,虚拟析构函数的语义与普通函数不同。析构函数是链式的,所以所有基类的析构函数都在第一个子类之后调用。但是,在常规方法的情况下,默认情况下不会调用覆盖方法的基本实现。需要时可以手动调用它们。