当一个类至少有一个虚拟成员函数而没有虚拟析构函数时,Visual C ++可以发出C4265 warning。
显然,当派生类对象通过指向基类的指针delete
并且基类中没有虚拟析构函数时,会发出警告。这种情况会产生不确定的行为。顺便说一句,我刚刚通过在Visual C ++中启用C4265,在相当庞大的代码库中找到了这种情况的一个例子。
默认情况下,此警告已关闭。
为什么呢?如果我启用它并向发出警告的每个类添加一个虚拟析构函数会发生什么?
答案 0 :(得分:3)
我的猜测是,有时你不需要虚拟析构函数,即使你确实有虚函数(因此考虑从中继承)。
如果在派生类中分配内存并且需要在对象销毁时释放它,则需要一个虚拟析构函数,但情况并非总是如此。
虚拟析构函数还意味着您应该实现一个复制构造函数和一个赋值运算符(三个规则),如果您的类成员只是POD类型,那么它们也是不需要的。
总而言之:即使对于不需要虚拟析构函数的类,您也会收到此警告,为什么要这样做?
答案 1 :(得分:2)
在link中,该警告的文档解释了微软的推理。 If a warning is off by default, most users would not want to see it.
答案 2 :(得分:1)
我认为使用模式Mixin类的人可能会发出很多警告。
WikiPedia:在面向对象的编程语言中,mixin是一个类,它提供某些功能可以继承或仅由子类重用,而不是用于实例化(该类的对象的生成)。 Mixins是抽象基类的同义词。从mixin继承不是一种专业化形式,而是一种收集功能的方法。类或对象可以从一个或多个mixin“继承”其大部分或全部功能,因此mixin可以被认为是多重继承的机制。
示例:
混合课程
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;
}
答案 3 :(得分:-4)
微软有时会对规范委员会未标明的“弃用功能”或某些“好的或坏的做法”发出警告。
如果该对象被设计为留在多态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更流畅了??)
唯一的好习惯是“如果你不知道自己在做什么,就不要做任何事情!”。 没有什么可以禁止接受建议,但“最佳实践”不是“总是好的做法”(否则它不会“最好”:只是“仅”)而编译器(作为正式工具)不应该警告主观性感受。