Java和C#支持使用final
和sealed
关键字不能用作基类的类的概念。但是,在C ++中,如果每个类都有一个虚拟的析构函数,那么就没有什么好的方法可以防止类的派生出于两难境地?
编辑:由于C ++ 11不再适用,您可以指定一个类为final
。
一方面给对象一个虚拟析构函数意味着它将具有vtable
,因此vptr
每个对象消耗4个(或64位机器上的8个)。
另一方面,如果有人后来从这个类派生并通过指向基类的指针删除派生类,程序将是错误定义的(由于没有虚拟析构函数),并坦率地优化指针每个对象都很荒谬。
在gripping hand 上有一个虚拟析构函数(可以说)宣告这种类型是多态的。
有些人认为你需要一个明确的理由不使用虚拟析构函数(正如this question的潜台词),而其他人则说只有当你有理由相信你的班级是派生自你的想法?
答案 0 :(得分:53)
每个抽象类都应该有一个
如果你有一个公共非虚拟析构函数,那就不好了,因为它允许用户通过该指针删除派生对象。因为我们都知道,这是未定义的行为。
对于不打算通过指向它的指针删除的类,没有任何理由拥有虚拟析构函数。它不仅会浪费资源,更重要的是它会给用户一个错误的提示。只要想想给std::iterator
一个虚拟析构函数会有什么蹩脚的感觉。
答案 1 :(得分:28)
问题是,您是否希望强制执行有关如何使用类的规则?为什么? 如果一个类没有虚拟析构函数,那么使用该类的任何人都知道它不是从中派生出来的,并且无论如何都要尝试它会有什么限制。那还不够好吗?
或者如果有人敢于做一些你没想过的事情,你是否需要编译器抛出一个硬错误?
如果您打算让人们从中派生,那么为该类提供一个虚拟析构函数。否则不要,并假设使用您的代码的任何人都足够聪明,可以正确使用您的代码。
答案 2 :(得分:8)
没有!仅当通过基类指针删除派生类的对象时才使用虚拟析构函数。如果您的类不打算在此场景中作为基础,请不要将析构函数设置为虚拟 - 您将发送错误的消息。
答案 3 :(得分:4)
检查this article from Herb Sutter:
准则#4:基类析构函数应该是公共的和虚拟的,或者是受保护的和非虚拟的。
答案 4 :(得分:2)
我对一般性问题“不”。不每个类都需要一个。如果您知道该类永远不应该继承,那么就不需要承担轻微的开销。但如果有机会,请保持安全,并将其放在那里。
答案 5 :(得分:1)
当基类包含至少一个纯虚函数时,基类成为抽象类。如果Base没有虚拟析构函数并且Derived(从Base派生),那么您可以通过Derived对象指针安全地销毁Derived对象,但不能通过Base对象指针销毁。
答案 6 :(得分:0)
我会补充一点,有些时候,当我在父母或子女班级忘记虚拟时,有一段时间我在破坏者没有被召唤的情况下划了一会儿。我想我现在知道要找那个了。 :)
有人可能会争辩说,有些时候父类会在析构函数中做一些孩子不应该做的事情......但这可能表明你的继承结构有问题。
答案 7 :(得分:-4)
include<iostream> using namespace std;
class base {
public: base() {
cout << "In base class constructor" << endl;
}
virtual ~base() {
cout << "in base class destuctor" << endl;
}
};
class derived : public base {
public: derived() {
cout << "in derived class constructor" << endl;
}
~derived() {
cout << "in derived class destructor" << endl;
}
};
int main() {
base *b; // pointer to the base
class b = new derived; // creating the derived class object using new
keyword;
delete b;
return 0;
}