衍生:C/C++基类的析构函数为什么必须定义为虚函数?
在实现多态时,当用基类操作派生类,在析构时防止只析构基类而不析构派生类的状况发生。
1)第一种情况:没有多态,创建派生类对象,基类的析构函数不是虚函数。
#includeusing namespace std; class ClxBase{ //基类 public: ClxBase() {}; ~ClxBase() { //析构函数不是虚函数 cout << "Output from the destructor of class ClxBase!" << endl; }; void DoSomething() { cout << "Do something in class ClxBase!" << endl; }; }; class ClxDerived : public ClxBase{ //派生类 public: ClxDerived() {}; ~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl; }; void DoSomething() { cout << "Do something in class ClxDerived!" << endl; }; }; int main(){ //没有多态,派生类对象 ClxDerived *p = new ClxDerived; p->DoSomething(); delete p; return 0; }
//运行结果 Do something in class ClxDerived! Output from the destructor of class ClxDerived! Output from the destructor of class ClxBase!
以上这段代码中基类的析构函数不是虚函数,在main函数中用派生类的指针去操作派生类的成员,释放指针P的过程是:先释放派生类的资源(执行~ClxDerived()) , 再释放基类资源(C++ primer里说编译器总是显示调用派生类对象基类部分的析构函数 ~ClxBase())。
2)第二种情况: 有多态,创建派生类对象,基类的析构函数不是虚函数
#includeusing namespace std; class ClxBase{ //基类 public: ClxBase() {}; ~ClxBase() { //析构函数不是虚函数 cout << "Output from the destructor of class ClxBase!" << endl; }; void DoSomething() { cout << "Do something in class ClxBase!" << endl; }; }; class ClxDerived : public ClxBase{ //派生类 public: ClxDerived() {}; ~ClxDerived() { cout << "Output from the destructor of class ClxDerived!" << endl; }; void DoSomething() { cout << "Do something in class ClxDerived!" << endl; } }; int main(){ ClxBase *p = new ClxDerived; //有多态 p->DoSomething(); delete p; return 0; }
//运行结果 Do something in class ClxBase! Output from the destructor of class ClxBase!
在以上这段代码中基类的析构函数同样不是虚函数,不同的是在main函数中用基类的指针去操作派生类的成员,释放过程: 只释放了基类的资源,而没有调用派生类的析构函数(因没有多态,静态绑定,只执行基类的析构函数~ClxBase() )。
一般情况下,这样的删除只能够删除基类对象,而不能删除子类对象,形成了删除一半的现象从而造成内存泄漏。
在公有继承中,基类对派生类及其对象的操作,只能影响到那些从基类继承下来的成员。如果想要用基类对非继承成员进行操作,则要把基类的这个函数定义为虚函数。
析构函数自然也应该如此:如果它想析构子类中重新定义或新的成员及对象,当然也应该声明为虚的。
3)第三种情况:有多态,创建派生类对象,基类的析构函数是虚函数。
释放过程:先释放了继承类的资源,再调用基类的析构函数。
衍生:什么是纯虚函数?抽象类又是什么?
在虚函数的后面写上=0,则这个函数为纯虚函数。包含纯虚函数的类叫抽象类(也叫接口类),抽象类不能实例化出对象。派生类继承后也不能实例化出对相关。只有重写纯虚函数,派生类才能实例化出对象。纯虚函数规范了派生类必须重写,另外纯虚函数更体现了接口继承。
衍生:多态的原理
1)虚函数表
以上sizeof(Base)大小为8字节,除了成员,还多了一个_vfptr放在对象的前面(有些平台可能会放在对象后面,跟平台有关),对象中的这个指针称为虚函数表指针。一个含有虚函数的类中至少有一个虚函数表指针,虚函数地址要被放到虚函数表中。



