c++中虚析构函数的作用是什么?
析构函数是为了在对象不被使用后释放它的资源,虚函数是为了实现多态。那么,把析构函数声明为virtual有什么作用呢? 请看下面代码:
- <span style="font-size:18px;">#include <iostream>
-
- using namespace std;
-
- class Base
- {
- public:
- Base(){ }
- ~Base()
- {
- cout<<"output from the destructor of class Base"<<endl;
- }
- virtual void Dosomething()
- {
- cout<<"do something in class Base"<<endl;
- }
- };
-
- class Derived : public Base
- {
- public:
- Derived(){ }
- ~Derived()
- {
- cout<<"output from the destructor of class Derived"<<endl;
- }
- void Dosomething()
- {
- cout<<"do something in class Derived"<<endl;
- }
- };
-
- int main()
- {
- Derived *pt1 = new Derived();
- pt1->Dosomething();
- delete pt1;
-
- Base *pt2 = new Derived();
- pt2->Dosomething();
- delete pt2;
-
- return 0;
- }</span>
程序输出:
- <span style="font-size:18px;">do something in class Derived
- output from the destructor of class Derived
- output from the destructor of class Base
- do something in class Derived
- output from the destructor of class Base</span>
代码37行可以正常释放pt1的资源,但是代码41行并没有正常释放pt2的资源,从结果看,Derived类的析构函数并没有被调用。通常情况下,类的析构函数里面都是释放内存资源,而析构函数不被调用的话就会造成内存泄漏。原因是指针pt2是Base类型的指针,释放pt2时只进行Base类的析构函数。在代码第9行加上virtual关键字后:
- do something in class Derived
- output from the destructor of class Derived
- output from the destructor of class Base
- do something in class Derived
- output from the destructor of class Derived
- output from the destructor of class Base
此时释放指针pt2时,由于Base的析构函数是virtual的,就会先找到并执行Derived类的析构函数,然后执行Base类的析构函数,资源正常释放,避免了内存泄漏。
因此,只有当一个类被用来作为基类的时候,才会把析构函数写成虚析构函数。
看代码写结果——析构函数的执行顺序
- #include <iostream>
-
- using namespace std;
-
- class A
- {
- private:
- int a;
- public:
- A(int aa) { a = aa; }
- ~A() { cout << "Destructor A!"<<a<<endl; }
- };
-
- class B : public A
- {
- private:
- int b;
- public:
- B(int aa=0, int bb=0):A(aa){ b = bb; }
- ~B(){ cout<<"Destructor B!"<<b<<endl;}
- };
-
- int main()
- {
- B obj1(5), obj2(6,7);
-
- return 0;
- }
本体考查的是析构函数的执行顺序。析构函数的执行顺序与构造函数的执行顺序相反。
main()函数中定义了两个类B的对象,它们的基类是A。由于这两个对象都是栈中分配的,当main()函数退出时会发生析构,又因为obj1比obj2先声明,所以obj2先析构。它们的顺序是首先执行B的析构函数,然后执行A的析构函数。
程序输出:
- Destructor B!7
- Destructor A!6
- Destructor B!0
- Destructor A!5