为什么C4265 Visual C++警告(虚拟成员函数且无虚拟析构函数)默认关闭?

发布于 2024-12-14 16:03:29 字数 349 浏览 2 评论 0原文

当以下情况发生时,Visual C++ 可能会发出 C4265 警告一个类至少有一个虚拟成员函数,并且没有虚拟析构函数。

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

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

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

Visual C++ can emit C4265 warning when a class has at least one virtual member function and no virtual destructor.

Obviously the warning is there to detect cases when a derived class object is deleted through a pointer to base class and there's no virtual destructor in the base class. Such situation yields undefined behavior. Btw I've just found an example of this situation in a rather huge codebase precisely by enabling C4265 in Visual C++.

And this warning is off by default.

Why? What would happen if I enabled it and added a virtual destructor to each class where the warning is emitted?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

唠甜嗑 2024-12-21 16:03:34

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

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

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

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

但不幸的是,OOP 是 C++ 最初支持的第一个范式,也是大多数程序员、流通书籍和教师参考的范式,因此他们部署了最佳实践“如果析构函数不是虚拟的,则不要派生”,不幸的是报道Scot Meyers 在他的《Effective C++》中也提到了这一点,因此使其变得“流行”,并且在没有技术原因使其继续存在的情况下也不断被提及。

今天,这种说法毫无意义,就像大多数“不要这样做,不要那样做”(包括 Dijkstra 著名的“goto 被认为是有害的”,它对结构化编程做出了很多新的强调,但也有许多荒谬的方式旋转只是为了避免它。哈...Miscrosoft 还没有关于使用 goto 的警告...可能 Meyers 比 Djikstra 更有影响力??)

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

Microsoft sometimes makes warning about "deprecated functions" that are not marked as such by the specification committee, or about certain "good or bad practice".

Having a non virtual destructor in an object that has virtual methods is a potential risk if that object is designed to leave in a polymorphic OOP environment (where delete pObject must properly also delete pDerived, even if viewed with pObject).
But this is just one of the paradigm C++ support... hence such a warning may be meaningless:

Also p->dosomething() doesn't call Derived::dosomething if dosomething isn't virtual, but no warning is generated for that.

To me delete p, pretending P::~P() to result in invoking D::~D() is not a special case, and should not deserve a warning.

But -unfortunately- OOP was the first paradigm C++ was initially supporting and the paradigm the most of programmers and circulating books and teachers refer to, so they deployed the best practice "don't derive if the destructor isn't virtual", unfortunately reported also by Scot Meyers in his "Effective C++", thus making it "popular" and continuously referred also if there is no technical reason for it to continue to exist.

Today is a non sense like the most of "don't do this, don't do that" (include the famous "goto considered harmful" by Dijkstra, that made a lot of new emphasis on structured programming but also many ridiculous ways to spin around just to avoid it. Ha ... Miscrosoft din't have a warning for the use of goto yet ... May be Meyers is more influent than Djikstra was ??)

The only good practice is "don't do ANYTHING if you don't know what you're doing!".
Nothing prohibits to accept suggestion, but a "best practoce" is not an "always good practice" (otherwise it will not "best": will just be "only") and a compiler (as a formal tool) should not warn about subjective feelings.

孤凫 2024-12-21 16:03:33

链接 中的文档该警告解释了微软的推理。 如果警告默认关闭,大多数用户都不想看到它。

In the link for the documentation for that warning it explains Microsoft's reasoning. If a warning is off by default, most users would not want to see it.

征棹 2024-12-21 16:03:33

我认为使用 Mixin 类模式的人可能会收到很多警告。

维基百科:在面向对象的编程语言中,mixin 是一个类,它提供某种功能供子类继承或重用,但不用于实例化(生成该类的对象)。 Mixins 是抽象基类的同义词。从 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;
}

I think a lot of warning can be among those who use the pattern Mixin classes.

WikiPedia: In object-oriented programming languages, a mixin is a class that provides a certain functionality to be inherited or just reused by a subclass, while not meant for instantiation (the generation of objects of that class). Mixins are synonymous with abstract base classes. Inheriting from a mixin is not a form of specialization but is rather a means of collecting functionality. A class or object may "inherit" most or all of its functionality from one or more mixins, therefore mixins can be thought of as a mechanism of multiple inheritance.

Example:

Mixed class

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);
  }
};

Use:

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;
}
墨洒年华 2024-12-21 16:03:32

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

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

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

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

My guess is that sometimes you don't need a virtual destructor, even if you do have virtual functions (and therefore think about inheriting from it).

You need a virtual destructor if you allocate memory in a derived class and need to free it on object destruction, but that's not always the case.

A virtual destructor also means you should implement a copy constructor and an assignment operator (the rule of three) which are also not needed if your class members are just POD types.

So to summarize: you would get this warning even for classes where you don't need the virtual destructor, so why have it?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文