首页 文章

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

提问于
浏览
57

我在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编译器给我一个警告说:

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

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

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

7 回答

  • 0

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

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

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

  • 2

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

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

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

  • 9

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

  • 64

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

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

  • 2

    我个人的观点是你做的正确,编译器坏了 . 如果可能,我将禁用警告(在文件中本地定义接口)

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

  • 4

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

  • 0

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

相关问题