可能重复:
GNU compiler warning “class has virtual functions but non-virtual destructor”
我正在为两个类编写一个接口,我在标题中收到警告。 这是代码:
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
};
只要构造函数/析构函数为void,将析构函数声明为protected就没有问题。当类使用堆时(析构函数被声明为受保护,无法将类从“外部”释放出来,使对象“不可破坏”),就会出现问题。 是否有更方便的方法(除了一路上市)?
答案 0 :(得分:11)
用作多态基的类应具有虚析构函数或受保护的析构函数。
原因是如果你有一个公共的,非虚拟的析构函数,那么该类的外部用户对它的任何使用都是不安全的。例如:
GenericSymbolGenerator *ptr = new PascalPredefinedSymbolGenerator();
delete ptr; // behavior is undefined, we tried to call the base class destructor
通过标记析构函数protected
,可以防止用户通过基类删除PascalPredefinedSymbolGenerator
对象。通过将析构函数设置为public virtual
,可以在用户通过基类删除时获得定义的行为。所以选择其中一个选项。
答案 1 :(得分:2)
我认为编译器是正确的,可以警告你基类中的非虚析构函数。您已经创建了一个明确打算作为继承层次结构的根的类,但是通过使基类析构函数非虚拟化,您已经破坏了通过指向基类的指针来删除对象的能力(就像所有这些一样) execution是基类的析构函数,因此不会采用派生类特定的操作)。这在C ++中被认为是一个非常糟糕的主意,因为当涉及到这个对象层次结构时,你实际上打破了多态的实现。
正如您在评论中提到的,您的意图是使用GenericSymbolGenerator作为接口,并强制用户实例化并使用包含实际实现代码的派生类。在C ++中声明接口的规范方法是将接口上的至少一个函数声明为纯虚函数。这会禁止您实例化基类,但仍会创建可实例化的派生类。您已经通过将generateSymbolTableCollection()
声明为基类中的纯虚函数来完成此操作。因此,您需要做的就是将析构函数设置为虚拟,因为在这种特定情况下它必须是虚拟的。
另外,默认构造函数和析构函数的规范签名通常是在不使用“void”作为参数的情况下编写的,只需使用空括号。