eclipse 类具有虚方法但非虚析构函数 C++
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12663998/
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
Class has virtual method but non virtual destructor C++
提问by Sebi
Possible Duplicate:
GNU compiler warning “class has virtual functions but non-virtual destructor”
I am writing an interface for two classes and I get the warning in the title. Here's the code:
我正在为两个类编写一个接口,我在标题中收到警告。这是代码:
class GenericSymbolGenerator {
protected: // <== ok
~GenericSymbolGenerator(void) {}
public:
virtual GenericSymbolTableCollection* generateSymbolTableCollection(GenericSymbolTableCollection *gst) = 0;
GenericSymbolGenerator(void) {}
// ~GenericSymbolGenerator(void) {} // <== warning if used
};
class PascalPredefinedSymbolGenerator : public GenericSymbolGenerator {
protected:
~PascalPredefinedSymbolGenerator(void) {} // <== ok
public:
GenericSymbolTableCollection* generateSymbolTableCollection(GenericSymbolTableCollection *pst); // initializes *pst
PascalPredefinedSymbolGenerator(void) {}
// ~PascalPredefinedSymbolGenerator(void) {} <== warning if used
};
class PascalSymbolGenerator : public GenericSymbolGenerator {
protected:
~PascalSymbolGenerator(void) {} // <== ok
public:
GenericSymbolTableCollection* generateSymbolTableCollection(GenericSymbolTableCollection *st); // initializes st
PascalSymbolGenerator(void) {}
// ~PascalSymbolGenerator(void) {} // <== warning if used
};
As long as the constructor/destructor is void there is no issue in declaring the destructor as protected. The problem arises when the class makes use of the heap(the destructor being declared as protected there is no way of freeing the class from the "outside" making the object "indestructible"). Is there a more convenient approach(aside from going public all the way)?
只要构造函数/析构函数为空,将析构函数声明为受保护就没有问题。当类使用堆时会出现问题(析构函数被声明为受保护,无法从“外部”释放类,使对象“不可破坏”)。有没有更方便的方法(除了一路上市)?
回答by Steve Jessop
Classes for use as polymorphic bases should have either a virtual destructor or a protected destructor.
用作多态基类的类应该具有虚拟析构函数或受保护的析构函数。
The reason is that if you have a public, non-virtual destructor, then pretty much any use of it by an external user of the class is unsafe. For example:
原因是,如果您有一个公共的、非虚拟的析构函数,那么该类的外部用户几乎对它的任何使用都是不安全的。例如:
GenericSymbolGenerator *ptr = new PascalPredefinedSymbolGenerator();
delete ptr; // behavior is undefined, we tried to call the base class destructor
By marking the destructor protected
, you prevent the user from deleting a PascalPredefinedSymbolGenerator
object via the base class. By making the destructor public and virtual
, you get defined behavior when the user deletes through the base class. So pick one of those options.
通过标记析构函数protected
,您可以防止用户PascalPredefinedSymbolGenerator
通过基类删除对象。通过将析构函数设为 public 和virtual
,当用户通过基类删除时,您将获得定义的行为。所以选择这些选项之一。
回答by Timo Geusch
I would argue that the compiler is correct to warn you about the non-virtual destructor in the base class. You have created a class that is clearly intended as the root of an inheritance hierarchy, but by making the base class destructor non-virtual, you've broken your ability to delete an object by pointer to the base class (as all that will be executed is the destructor of the base class, so no derived class specific actions will be taken). This is considered a really bad idea in C++ as you essentially break the implementation of polymorphism when it comes to this object hierarchy.
我认为编译器警告你基类中的非虚拟析构函数是正确的。您已经创建了一个明确打算作为继承层次结构根的类,但是通过使基类析构函数非虚拟,您已经破坏了通过指向基类的指针删除对象的能力(因为所有这些都将是执行的是基类的析构函数,因此不会采取派生类特定的操作)。这在 C++ 中被认为是一个非常糟糕的主意,因为当涉及到这个对象层次结构时,你本质上破坏了多态的实现。
As you mentioned in your comments, your intent is to use GenericSymbolGenerator as an interface and force the user to instantiate and use derived classes containing the actual implementation code. The canonical way to declare an interface in C++ is to declare at least one function on the interface as a pure virtual function. This prohibits you from instantiating the base class, but still create instantiable derived classes. You've already done this by declaring generateSymbolTableCollection()
as a pure virtual function in your base class. So all you need to do is make the destructor virtual as it really has to be virtual in this particular scenario.
正如您在评论中提到的,您的意图是使用 GenericSymbolGenerator 作为接口并强制用户实例化和使用包含实际实现代码的派生类。在 C++ 中声明接口的规范方法是将接口上的至少一个函数声明为纯虚函数。这会阻止您实例化基类,但仍然创建可实例化的派生类。您已经通过generateSymbolTableCollection()
在基类中声明为纯虚函数来完成此操作。所以你需要做的就是让析构函数成为虚拟的,因为在这个特定场景中它真的必须是虚拟的。
Also, as an aside, the canonical signatures for the default constructor and destructor are normally written without using "void" as a parameter, just use the empty parentheses instead.
此外,顺便说一句,默认构造函数和析构函数的规范签名通常在编写时不使用“void”作为参数,只需使用空括号代替。