C++ GNU 编译器警告“类具有虚函数但非虚析构函数”
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/127426/
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
GNU compiler warning "class has virtual functions but non-virtual destructor"
提问by Paolo Tedesco
I have defined an interface in C++, i.e. a class containing only pure virtual functions.
我在 C++ 中定义了一个接口,即一个只包含纯虚函数的类。
I want to explicitly forbid users of the interface to delete the object through a pointer to the interface, so I declared a protected and non-virtual destructor for the interface, something like:
我想明确禁止接口的用户通过指向接口的指针删除对象,所以我为接口声明了一个受保护的非虚拟析构函数,例如:
class ITest{
public:
virtual void doSomething() = 0;
protected:
~ITest(){}
};
void someFunction(ITest * test){
test->doSomething(); // ok
// deleting object is not allowed
// delete test;
}
The GNU compiler gives me a warning saying:
GNU 编译器给了我一个警告说:
class 'ITest' has virtual functions but non-virtual destructor
“ITest”类具有虚函数但非虚析构函数
Once the destructor is protected, what is the difference in having it virtual or non-virtual?
一旦析构函数受到保护,它是虚拟的还是非虚拟的有什么区别?
Do you think this warning can be safely ignored or silenced?
您认为可以安全地忽略或消除此警告吗?
回答by Greg Rogers
It's more or less a bug in the compiler. Note that in more recent versions of the compiler this warning does not get thrown (at least in 4.3 it doesn't). Having the destructor be protected and non-virtual is completely legitimate in your case.
它或多或少是编译器中的错误。请注意,在更新版本的编译器中,不会抛出此警告(至少在 4.3 中不会)。在您的情况下,让析构函数受到保护和非虚拟是完全合法的。
See herefor an excellent article by Herb Sutter on the subject. From the article:
请参阅此处以获取 Herb Sutter 关于该主题的一篇出色文章。从文章:
Guideline #4: A base class destructor should be either public and virtual, or protected and nonvirtual.
准则#4:基类析构函数应该是public 和virtual,或者protected 和nonvirtual。
回答by Airsource Ltd
Some of the comments on this answer relate to an earlier answer I gave, which was wrong.
关于这个答案的一些评论与我之前给出的答案有关,这是错误的。
A protected destructor means that it can only be called from a base class, not through delete. That means that an ITest* cannot be directly deleted, only a derived class can. The derived class may well want a virtual destructor. There is nothing wrong with your code at all.
受保护的析构函数意味着它只能从基类调用,不能通过删除调用。这意味着不能直接删除 ITest*,只有派生类可以。派生类可能需要一个虚拟析构函数。您的代码完全没有问题。
However, since you cannot locally disable a warning in GCC, and you already have a vtable, you could consider just making the destructor virtual anyway. It will cost you 4 bytes for the program (not per class instance), maximum. Since you might have given your derived class a virtual dtor, you may find that it costs you nothing.
但是,由于您无法在 GCC 中本地禁用警告,并且您已经有一个 vtable,因此您可以考虑将析构函数设为虚拟。程序最多需要 4 个字节(不是每个类实例)。由于您可能已经为您的派生类提供了一个虚拟 dtor,您可能会发现它没有任何成本。
回答by bk1e
If you insist on doing this, go ahead and pass -Wno-non-virtual-dtor
to GCC. This warning doesn't seem to be turned on by default, so you must have enabled it with -Wall
or -Weffc++
. However, I think it's a useful warning, because in most situations this would be a bug.
如果您坚持这样做,请继续并传递-Wno-non-virtual-dtor
给 GCC。默认情况下,此警告似乎未打开,因此您必须使用-Wall
或启用它-Weffc++
。但是,我认为这是一个有用的警告,因为在大多数情况下这将是一个错误。
回答by MSalters
It's an interface class, so it's reasonable you should not delete objects implementing that interface via that interface. A common case of that is an interface for objects created by a factory which should be returned to the factory. (Having objects contain a pointer to their factory might be quite expensive).
它是一个接口类,因此不应该删除通过该接口实现该接口的对象是合理的。一个常见的情况是由工厂创建的对象的接口应该返回给工厂。(让对象包含指向其工厂的指针可能会非常昂贵)。
I'd agree with the observation that GCC is whining. Instead, it should simply warn when you delete an ITest*. That's where the real danger lies.
我同意海湾合作委员会正在抱怨的观察。相反,它应该只是在您删除 ITest* 时发出警告。这才是真正的危险所在。
回答by Len Holgate
My personal view is that you'd doing the correct thing and the compiler is broken. I'd disable the warning (locally in the file which defines the interface) if possible,
我个人的观点是,你做了正确的事情,编译器坏了。如果可能,我会禁用警告(本地在定义接口的文件中),
I find that I use this pattern (small 'p') quite a lot. In fact I find that it's more common for my interfaces to have protected dtors than it is for them to have public ones. However I don't think it's actually that common an idiom (it doesn't get spoken about that much) and I guess back when the warning was added to GCC it was appropriate to try and enforce the older 'dtor must be virtual if you have virtual functions' rule. Personally I updated that rule to 'dtor must be virtual if you have virtual functions and wish users to be able to delete instances of the interface through the interface else the dtor should be protected and non virtual' ages ago ;)
我发现我经常使用这种模式(小“p”)。事实上,我发现我的接口拥有受保护的 dtor 比拥有公共的更常见。但是我不认为它实际上是一个常见的习语(它没有被谈论那么多)我猜回到当警告被添加到 GCC 时,尝试强制执行旧的 'dtor must be virtual 是合适的,如果你有虚函数规则。我个人将该规则更新为“如果您有虚拟功能并希望用户能够通过界面删除界面的实例,则 dtor 必须是虚拟的,否则 dtor 应该受到保护并且是非虚拟的”很久以前;)
回答by Adam Rosenfield
If you had code in one of ITest
's methods that tried to delete
itself (a bad idea, but legal), the derived class's destructor wouldn't be called. You should still make your destructor virtual, even if you never intend to delete a derived instance via a base-class pointer.
如果您在ITest
's 的方法中的一个尝试delete
自己的代码(一个坏主意,但合法),则不会调用派生类的析构函数。即使您从不打算通过基类指针删除派生实例,您仍然应该使析构函数成为虚拟的。
回答by INS
If the destructor is virtual it makes sure that the base class destructor is also called fore doing the cleanup, otherwise some leaks can result from that code. So you should make sure that the program has no such warnings (prefferably no warnings at all).
如果析构函数是虚拟的,它确保在执行清理之前也调用基类析构函数,否则该代码可能会导致一些泄漏。所以你应该确保程序没有这样的警告(最好根本没有警告)。