c++之——虚析构函数

先看代码:

  1 #include<iostream>
  2 using namespace std;
  3 
  4 class Parent {
  5 public:
  6     Parent() :a(100), b(200), c(300)
  7     {
  8         
  9         p = new char[10];
 10         //strcpy(p, "abc");
 11         cout << "parent 无参构造。。。
";
 12     }
 13     Parent(int test) :a(1000), b(2000), c(3000)
 14     {
 15         p = new char[10];
 16         //strcpy(p, "abc");
 17         cout << "parent 有参构造。。。
";
 18     }
 19     ~Parent()
 20     {
 21         delete[] p;
 22         cout << "Parent 析构。。。
";
 23     }
 24     int a;
 25     int b;
 26     int c;
 27     char *p;
 28     void p_print()
 29     {
 30         cout << "a b c is" << a << " " << b << " " << c << endl;
 31     }
 32 
 33 };
 34 class Child1 :  public Parent
 35 {
 36 public:
 37     Child1() :Parent(1),a(10), b(0), c(0) 
 38     { 
 39         p = new char[10];
 40     //    strcpy(p, "abc");
 41         cout << "child1 构造
";
 42     }
 43     ~Child1()
 44     {
 45         delete[] p;
 46         cout << "child1 析构,,,
";
 47     }
 48     void c1_print()
 49     {
 50         cout << "a b c is" << a << " " << b << " " << c << endl;
 51     }
 52 
 53     int a;
 54     int b;
 55     int c;
 56     char *p;
 57 };
 58 class Child2 :  public Child1
 59 {
 60 public:
 61     Child2() :Child1(), b(2), c(3) 
 62     { 
 63         p = new char[10];
 64         //strcpy(p, "abc");
 65         cout << "child2 构造
"; 
 66     }
 67     ~Child2()
 68     {
 69         delete[] p;
 70         cout << "child2 析构,,,
";
 71     }
 72     void c2_print()
 73     {
 74         cout << "a b c is" << Parent::a << " " << b << " " << c << endl;
 75     }
 76     //int a;
 77     int b;
 78     int c;
 79     char *p;
 80 };
 81 /*
 82 class Child3 : public Child1, public Child2
 83 {
 84 public:
 85     Child3() : Child1(), Child2(), b(20), c(30) { cout << "child 构造
"; }
 86     ~Child3()
 87     {
 88         cout << "child 析构,,,
";
 89     }
 90     void c3_print()
 91     {
 92         cout << "a b c is" << a << " " << b << " " << c << endl;
 93     }
 94     //int a;
 95     int b;
 96     int c;
 97 };
 98 */
 99 void play()
100 {
101     Child2* c2 = new Child2;
102     delete c2;
103 }
104 int main()
105 {
106     //Child2* c2 = new Child2;
107     play();
108     return 0;
109 }

这样是没问题的(c++编译器会以构造相反的顺序执行析构函数),但是,在很多时候,我们不能在调用函数末尾就delete掉这个内存,还需要和后续交互。比如作为函数参数,为了实现多态,我们函数参数是父类的指针,所以更常见和一般的设计思维是更改paly和main函数如下:

 1 void play(Parent* p)
 2 {
 3     delete p;
 4 }
 5 int main()
 6 {
 7     Child2* c2 = new Child2;
 8     play(c2);
 9     return 0;
10 }

运行结果显示内存泄漏了,只析构了父类;所以我们有那么一种需求,要想和多态的效果一样,传什么指针去,自动析构应该析构的东西,更改代码,实现虚析构函数。

只用更改基类的析构函数,加上virtual关键字:

1     virtual ~Parent()
2     {
3         delete[] p;
4         cout << "Parent 析构。。。
";
5     }

这样就没有内存泄漏了。

知识简要:

 如果基类的析构函数不是虚函数,则delete一个指向派生类对象的基类指针将产生未定义的行为。之前我们介绍过一个准则,如果一个类需要析构函数,那么它同样需要拷贝和赋值操作。基类的析构函数并不遵循上述准则,它是一个重要的例外。

原文地址:https://www.cnblogs.com/yangguang-it/p/6534510.html