GNU编译器警告“类具有虚函数但非虚析构函数”

时间:2008-09-24 14:16:22

标签: c++ gcc

我在C ++中定义了一个接口,即一个只包含纯虚函数的类。

我想明确禁止接口的用户通过指向接口的指针删除对象,所以我为接口声明了一个受保护的非虚拟析构函数,如:

class ITest{
public:
    virtual void doSomething() = 0;

protected:
    ~ITest(){}
};

void someFunction(ITest * test){
    test->doSomething(); // ok
    // deleting object is not allowed
    // delete test; 
}

GNU编译器给我一个警告说:

  

类'ITest'具有虚函数但非虚析构函数

一旦析构函数受到保护,虚拟或非虚拟有什么区别?

你认为这个警告可以被安全地忽略或者沉默吗?

7 个答案:

答案 0 :(得分:65)

这或多或少是编译器中的一个错误。请注意,在更新版本的编译器中,此警告不会被抛出(至少在4.3中它没有)。在您的情况下,让析构函数受到保护并且非虚拟化是完全合法的。

请参阅here,了解Herb Sutter关于此主题的精彩文章。来自文章:

准则#4:基类析构函数应该是公共的和虚拟的,或者是受保护的和非虚拟的。

答案 1 :(得分:9)

这个答案的一些评论与我之前给出的答案有关,这是错误的。

受保护的析构函数意味着它只能从基类调用,而不能通过删除调用。这意味着不能直接删除ITest *,只能派生类。派生类可能需要虚拟析构函数。你的代码完全没有问题。

但是,由于您无法在GCC中本地禁用警告,并且您已经拥有了vtable,因此您可以考虑将析构函数设置为虚拟。它将花费你4个字节的程序(不是每个类实例),最大。由于您可能已将您的派生类赋予虚拟dtor,因此您可能会发现它不需要任何费用。

答案 2 :(得分:4)

如果您坚持这样做,请继续将-Wno-non-virtual-dtor传递给GCC。默认情况下,此警告似乎未启用,因此您必须使用-Wall-Weffc++启用此警告。但是,我认为这是一个有用的警告,因为在大多数情况下,这将是一个错误。

答案 3 :(得分:2)

这是一个接口类,所以你不应该删除通过该接口实现该接口的对象。一个常见的情况是工厂创建的对象的接口应该返回工厂。 (对象包含指向其工厂的指针可能非常昂贵)。

我同意海湾合作委员会抱怨的观点。相反,它应该只是在您删除ITest *时发出警告。这就是真正的危险所在。

答案 4 :(得分:2)

我个人认为你做的是正确的事情,编译器坏了。如果可能的话,我会禁用警告(在文件中本地定义接口),

我发现我使用这种模式(小'p')非常多。事实上,我发现我的接口拥有受保护的dtors比使用公共接口更常见。然而,我不认为它实际上是常见的成语(它没有得到那么多的说法),我想回来时,警告被添加到GCC是适当的尝试并强制执行旧的'dtor必须是虚拟的,如果你有虚函数的规则。我个人更新了规则,如果你有虚拟功能,并且希望用户能够通过界面删除界面实例,那么dtor必须是虚拟的,否则dtor应该受到保护,非虚拟'很久以前;)

答案 5 :(得分:0)

如果析构函数是虚拟的,它确保在执行清理之前也调用基类析构函数,否则可能会导致某些泄漏。所以你应该确保程序没有这样的警告(最好没有警告)。

答案 6 :(得分:0)

如果你的ITest方法之一的代码试图delete本身(一个坏主意,但合法),则不会调用派生类的析构函数。即使你从未打算通过基类指针删除派生实例,你仍然应该使析构函数成为虚拟的。