C++ 类具有虚方法但非虚析构函数C++;

C++ 类具有虚方法但非虚析构函数C++;,c++,eclipse,methods,virtual,C++,Eclipse,Methods,Virtual,可能重复: 我正在为两个类编写一个接口,我在标题中得到了警告。 代码如下: class GenericSymbolGenerator { protected: // <== ok ~GenericSymbolGenerator(void) {} public: virtual GenericSymbolTableCollection* generateSymbolTableCollection(GenericSymb

可能重复:

我正在为两个类编写一个接口,我在标题中得到了警告。 代码如下:

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
};
类GenericSymbolGenerator{

protected://我认为编译器警告您基类中的非虚拟析构函数是正确的。您创建的类显然是作为继承层次结构的根,但通过使基类析构函数非虚拟,您破坏了通过指向基类(所有要执行的是基类的析构函数,因此不会使用派生类特定的动作)。这在C++中被认为是一个非常糟糕的想法,因为在涉及到对象层次结构时,基本上打破了多态性的实现。

正如您在您的评论中提到的,您的意图是使用GuangCigBug生成器作为接口,并强制用户实例化并使用包含实际实现代码的派生类。在C++中声明接口的规范方式是在接口上声明至少一个函数作为纯虚函数。从实例化基类开始,但仍然创建可实例化的派生类。您已经通过在基类中将

generateSymbolTableCollection()
声明为纯虚拟函数来实现了这一点。因此,您所需要做的就是使析构函数虚拟化,因为在这个特定场景中它实际上必须是虚拟的


另外,默认构造函数和析构函数的规范签名通常不使用“void”作为参数编写,只需使用空括号即可。用作多态基的类应具有虚拟析构函数或受保护的析构函数

原因是,如果您有一个公共的、非虚拟的析构函数,那么该类的外部用户使用它几乎是不安全的。例如:

GenericSymbolGenerator *ptr = new PascalPredefinedSymbolGenerator();
delete ptr; // behavior is undefined, we tried to call the base class destructor

通过将析构函数
标记为protected
,可以防止用户通过基类删除
PascalPredefinedSymbolGenerator
对象。通过将析构函数设置为public和
virtual
,可以在用户通过基类删除时获得定义的行为。因此,请选择其中一个选项。

为什么要使析构函数受保护?这只是在接口必须完全限于用户的情况下出现的一种情况。>您可以进一步澄清您的问题吗?>为什么需要公共构造函数和受保护的析构函数?>因为析构函数应该是虚拟的。因此,当您销毁子类的对象时,它会调用基类。这只是一个例子(我的接口构造函数/析构函数都是空的)。我对一种情况很感兴趣。@Sebi,我不太确定我是否遵循了你的推理。你是说你想限制对象层次结构的使用,只允许使用派生类的实例吗?如果是这样,那么保护析构函数是错误的做法。保护析构函数(或私人)意味着客户端代码永远不能通过基类指针删除派生类对象。因此,在这种情况下,不需要使用虚拟析构函数。请参阅链接的dupe。我已经完成了dupe。那里的析构函数也无效。这就是为什么我问了一个新问题。@Sebi你说的
析构函数无效是什么意思?
s平凡,即主体为空?它具有默认实现(不改变类成员/内存).-1,因为
delete
ing一个基指针是UB,而不是某种半破坏。在我的情况下,声明析构函数为虚拟更有用。声明析构函数为受保护不是防止删除实例化的派生对象吗?@Sebi:不,它只防止通过指向基的指针删除它们。它们仍然可以被删除如果您的派生类对用户隐藏,用户只需调用一些工厂函数,返回一个智能指针,知道删除它的类型,那么您就可以使用
受保护的
析构函数。@Sebi-FWIW,这是您问题的正确答案,而不是您选择的。@Steve谢谢,我找到了现在。