Visual C++ 会发出 C4265 警告。
显然,警告是为了检测派生类对象通过指向基类的指针进行
delete
d 并且基类中没有虚拟析构函数的情况。这种情况会产生未定义的行为。顺便说一句,我刚刚通过在 Visual C++ 中启用 C4265,在相当大的代码库中找到了这种情况的示例。
默认情况下此警告处于关闭状态。
为什么?如果我启用它并向发出警告的每个类添加虚拟析构函数,会发生什么?
我的猜测是,有时您不需要虚拟析构函数,即使您确实有虚拟函数(因此考虑从它继承)。
如果您在派生类中分配内存并需要在对象销毁时释放它,则需要虚拟析构函数,但情况并非总是如此。
虚拟析构函数还意味着您应该实现复制构造函数和赋值运算符(三规则),如果您的类成员只是 POD 类型,则也不需要这些。
总结一下:即使对于不需要虚拟析构函数的类,您也会收到此警告,那么为什么要使用它呢?
在该警告文档的链接中,它解释了 Microsoft 的推理。
If a warning is off by default, most users would not want to see it.
我认为使用 Mixin 类模式的人可能会受到很多警告。
WikiPedia:在面向对象的编程语言中,mixin 是一个类,它提供某种功能供子类继承或重用,但不用于实例化(生成该类的对象)。 Mixin 是抽象基类的同义词。从 mixin 继承并不是一种专门化的形式,而是一种收集功能的方法。一个类或对象可以从一个或多个 mixins 中“继承”其大部分或全部功能,因此 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;
}
微软有时会对规范委员会未标记为“已弃用的功能”或某些“好的或坏的做法”发出警告。
如果该对象被设计为留在多态 OOP 环境中(其中
delete pObject
也必须正确地 delete pDerived
,即使使用 pObject
查看),那么在具有虚拟方法的对象中拥有非虚拟析构函数是一个潜在风险。
但这只是 C++ 支持的范例之一......因此这样的警告可能毫无意义:
此外,如果
p->dosomething()
不是虚拟的,则 Derived::dosomething
不会调用 dosomething
,但不会为此生成警告。
对我来说
delete p
,假装 P::~P()
导致调用 D::~D()
并不是特例,不应该受到警告。
但不幸的是,OOP 是 C++ 最初支持的第一个范式,也是大多数程序员、流通书籍和教师参考的范式,因此不幸的是,他们部署了最佳实践“如果析构函数不是虚拟的,则不要派生” Scot Meyers 在他的《Effective C++》中也对此进行了报道,从而使其变得“流行”,并且在没有技术原因使其继续存在的情况下也不断被提及。
今天是一个无意义的事情,就像大多数“不要这样做,不要那样做”(包括 Dijkstra 著名的“goto 被认为是有害的”,它对结构化编程做出了很多新的强调,但也有许多荒谬的方式旋转只是为了避免它。哈...Miscrosoft 还没有使用 goto 的警告...可能 Meyers 比 Djikstra 更有影响力??)
唯一的好习惯是“如果你不知道自己在做什么,就不要做任何事情!”。 没有什么禁止接受建议,但“最佳实践”并不是“总是好的实践”(否则它不会是“最佳”:只是“唯一”)并且编译器(作为正式工具)不应警告主观感受。