类具有虚拟方法,但具有非虚拟析构函数C++
Class has virtual method but non virtual destructor C++
可能重复:
GNU编译器警告“类具有虚拟函数但非虚拟析构函数;
我正在为两个类编写一个接口,标题中出现了警告。这是代码:
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就没有问题。当类使用堆时,问题就出现了(析构函数被声明为受保护的——没有办法将类从"外部"释放出来,使对象"坚不可摧")。有没有更方便的方法(除了一直公开)?
用作多态基的类应该具有虚拟析构函数或受保护的析构函数。
原因是,如果您有一个公共的、非虚拟的析构函数,那么该类的外部用户对它的任何使用都是不安全的。例如:
GenericSymbolGenerator *ptr = new PascalPredefinedSymbolGenerator();
delete ptr; // behavior is undefined, we tried to call the base class destructor
通过标记析构函数protected
,可以防止用户通过基类删除PascalPredefinedSymbolGenerator
对象。通过公开析构函数和virtual
,可以在用户通过基类进行删除时获得定义的行为。因此,选择其中一个选项。
我认为编译器警告基类中的非虚拟析构函数是正确的。您已经创建了一个类,该类显然是继承层次结构的根,但通过使基类析构函数为非虚拟的,您破坏了通过指向基类的指针来删除对象的能力(因为所有将执行的都是基类的析构函数,因此不会采取派生类特定的操作)。这在C++中被认为是一个非常糟糕的想法,因为当涉及到这个对象层次结构时,你基本上破坏了多态性的实现。
正如您在评论中提到的,您的意图是使用GenericSymbolGenerator作为接口,并强制用户实例化和使用包含实际实现代码的派生类。在C++中声明接口的规范方法是将接口上的至少一个函数声明为纯虚拟函数。这禁止您实例化基类,但仍然可以创建可实例化的派生类。您已经通过在基类中将generateSymbolTableCollection()
声明为纯虚拟函数来实现了这一点。所以你所需要做的就是使析构函数成为虚拟的,因为在这个特定的场景中,它必须是虚拟的。
此外,顺便说一句,默认构造函数和析构函数的规范签名通常是在不使用"void"作为参数的情况下编写的,只需使用空括号即可。
- 重载 -> shared_ptr 个实例中的箭头运算符<interface>,接口中没有纯虚拟析构函数
- 是否可以使用函数指针调用虚拟析构函数?
- 在没有动态内存的世界中,我是否需要虚拟析构函数?
- 程序永远不会进入虚拟析构函数
- C++ std::vector 中的虚拟析构函数继承
- 哪种方法更适合处理虚拟析构函数?
- 拥有"受保护的非虚拟析构函数"与"受保护虚拟析构构函数"有什么好处
- 带有未解析外部元素的C++虚拟析构函数
- 即使基类和派生类只使用基元数据类型,我是否需要定义虚拟析构函数
- C++切片和虚拟析构函数
- C++虚拟继承、虚拟析构函数和 dynamic_cast<void*>
- 添加虚拟析构函数会使代码大小膨胀
- 应该是虚拟析构函数吗?但是怎么做呢?
- 虚拟析构函数将对象移出 rodata 部分
- 如何将 std::unique_ptr<Parent> 与具有受保护虚拟析构函数的只读父类一起使用
- DIRECTX9 中自定义顶点的虚拟析构函数
- 为什么缺少虚拟析构函数不会导致内存泄漏?
- std::unique_ptr 在虚拟析构函数上重置 SIGABRT
- C++11 中默认纯虚拟析构函数的正确放置
- 在派生类中重写哪个基类的虚拟析构函数