【问题标题】:Why is C4265 Visual C++ warning (virtual member function and no virtual destructor) off by default?为什么默认关闭 C4265 Visual C++ 警告(虚拟成员函数和无虚拟析构函数)?
【发布时间】:2011-11-08 13:38:26
【问题描述】:

当类具有至少一个虚成员函数且没有虚析构函数时,Visual C++ 可以发出 C4265 warning

很明显,当派生类对象通过指向基类的指针为deleted 并且基类中没有虚拟析构函数时,会出现警告。这种情况会产生未定义的行为。顺便说一句,我刚刚通过在 Visual C++ 中启用 C4265,在相当大的代码库中找到了这种情况的示例。

而且这个警告默认是关闭的。

为什么?如果我启用它并向发出警告的每个类添加一个虚拟析构函数会发生什么?

【问题讨论】:

    标签: c++ visual-c++ compiler-construction destructor compiler-warnings


    【解决方案1】:

    我的猜测是,有时您不需要虚拟析构函数,即使您确实有虚拟函数(因此考虑从它继承)。

    如果您在派生类中分配内存并需要在对象销毁时释放它,则需要一个虚拟析构函数,但情况并非总是如此。

    虚拟析构函数还意味着您应该实现一个复制构造函数和一个赋值运算符(三个规则),如果您的类成员只是 POD 类型,它们也不需要。

    总结一下:即使对于不需要虚拟析构函数的类,您也会收到此警告,那么为什么要使用它?

    【讨论】:

    • 我不认为三法则是这样的。一个空的虚拟析构函数足以进行多态删除。与您已经获得的析构函数完全相同(由编译器提供),只是virtual
    【解决方案2】:

    link 的警告文档中,它解释了微软的推理。 If a warning is off by default, most users would not want to see it.

    【讨论】:

    • 注意一个非常常见的情况,C4265 将触发(如果你启用了它)是实现没有定义虚拟 dtors 的“接口”(即抽象虚拟类)。一个简单的解决方法是将您的班级标记为final,表示没有人会从您的班级派生,所以没关系。
    • 请注意,Visual C++ 中的 C4265 与 clang/LLVM 中的 -Wnon-virtual-dtor 和/或 -Wdelete-non-abstract-non-virtual-dtor 具有相同的警告。
    • 实际上它们并不相同。在类具有非虚拟析构函数的情况下,Visual C++(至少某些版本)似乎会发出警告,即使该析构函数是受保护的或私有的。相比之下,如果析构函数是受保护的或私有的,clang 不会抱怨。区别很重要;见isocpp.github.io/CppCoreGuidelines/…
    【解决方案3】:

    我认为在使用模式 Mixin 类的人中会有很多警告。

    WikiPedia:在面向对象的编程语言中,mixin 是一个类,它提供了可以被子类继承或重用的特定功能,而不是用于实例化(生成该类的对象)。 Mixin 是抽象基类的同义词。从 mixin 继承不是一种专业化形式,而是一种收集功能的方法。一个类或对象可以从一个或多个 mixin 中“继承”其大部分或全部功能,因此可以将 mixins 视为一种多重继承机制。

    例子:

    混合班

    template <typename T> struct AddNoEq {
      virtual bool operator==(const T &cmp) const = 0;
      bool operator!=(const T &cmp) const {
        return !static_cast<const T*>(this)->operator== (cmp);
      }
    };
    

    用途:

    struct Complex : public AddNoEq<Complex> {
      Complex(int re, int im): re_(re), im_(im) { }
    
      virtual bool operator==(const Complex& cmp) const {
          return cmp.re_ == this->re_ && cmp.im_ == this->im_;
      }
      // ...
    private:
      int re_, im_;
    };
    
    int main()
    {
      Complex a(1, 2), b(2, 3);
    
        if (a != b)
          std::cout << "OK!" << std::endl;
    
        return 0;
    }
    

    【讨论】:

      【解决方案4】:

      Microsoft 有时会对规范委员会未标记的“已弃用功能”或某些“好的或坏的做法”发出警告。

      如果该对象被设计为离开多态 OOP 环境(其中delete pObject 必须正确地也正确地也delete pDerived,即使使用pObject 查看,那么在具有虚方法的对象中具有非虚析构函数是潜在的风险。 )。 但这只是范式 C++ 支持之一......因此这样的警告可能毫无意义:

      如果dosomething 不是虚拟的,p-&gt;dosomething() 也不会调用Derived::dosomething,但不会为此生成警告。

      对我 delete p 来说,假装 P::~P() 导致调用 D::~D() 不是特殊情况,不应该受到警告。

      但不幸的是,OOP 是 C++ 最初支持的第一个范式,也是大多数程序员、流通书籍和教师所引用的范式,因此他们部署了最佳实践“如果析构函数不是虚拟的,就不要派生” ,不幸的是,Scot Meyers 在他的“Effective C++”中也报道了它,因此使其“流行”并且如果没有技术理由继续存在,它也会被不断引用。

      今天就像大多数“不要这样做,不要那样做”一样毫无意义(包括 Dijkstra 著名的“goto 被认为有害”,它对结构化编程进行了很多新的强调,但也有很多为了避免它而旋转的荒谬方式。哈...微软尚未对使用 goto 发出警告...可能是 Meyers 比 Djikstra 更有影响力??)

      唯一好的做法是“如果您不知道自己在做什么,就不要做任何事情!”。 没有什么可以禁止接受建议,但是“最佳实践”并不是“总是好的实践”(否则它不会是“最好的”:只会是“唯一的”)并且编译器(作为正式工具)不应该警告主观感觉。

      【讨论】:

        猜你喜欢
        • 2011-09-30
        • 2014-01-30
        • 2010-10-24
        • 2012-04-18
        • 2015-11-12
        • 2017-04-21
        • 1970-01-01
        • 2010-11-10
        • 2011-08-12
        相关资源
        最近更新 更多