C++ 消失的析构函数 —— virtual 实现的动态析构

在C++类的结构中可以使用类方法创建内存,使用类的析构函数去施放内存,但有这么一种情况会导致:即使在析构函数中释放了内存,但由于析构函数没有被调用而导致内存泄漏,如下代码。

 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 class Father
 7 {
 8 public:
 9     Father(const char* addr = "Father 带参构造")
10     {
11         cout << "执行了 Father 的构造函数" << endl;
12         int len = strlen(addr) + 1;
13         this->addr = new char[len];
14         strcpy_s(this->addr, len, addr);
15     }
16 
17     ~Father()
18     {
19         cout << "执行了 Father 的析构函数" << endl;
20         if (this->addr)
21         {
22             delete addr;
23             addr = NULL;
24         }
25     }
26 private:
27     char *addr;
28 };
29 
30 
31 class Son :public Father
32 {
33 public:
34     Son(const char *game = "Son 带参构造", const char *addr = "继承 Father 带参构造" ) :Father(addr)
35     //Son(const char* game = "Son 带参构造")
36     {
37         cout << "执行了 Son 的构造函数" << endl;
38         int len = strlen(game) + 1;
39         this->game = new char[len];
40         strcpy_s(this->game, len, game);
41     }
42     ~Son()
43     {
44         cout << "执行了 Son 的析构函数" << endl;
45         if (this->game)
46         {
47             delete game;
48             game = NULL;
49         }
50     }
51 
52 private:
53     char* game;
54 };
55 
56 int main()
57 {
58     cout << "--------case 1----------" <<endl;
59     Father* father = new Father();
60     delete father;
61 
62     cout << "\n--------case 2----------" << endl;
63     Son* son = new Son();
64     delete son;
65 
66     cout << "\n--------case 3----------" << endl;
67     father = new Son();
68     delete father;
69 
70     return 0;
71 }

运行结果:

 以上打印,case 1和case 2都正常。再看67行代码,在看 case 3 的打印,会发现少释放一个 Son ,

而解决这个问题也很简单,讲父类的析构函数修饰为虚函数便可。还是上边的代码,第17行,父类析构函数前增加 virtual:

 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 class Father
 7 {
 8 public:
 9     Father(const char* addr = "Father 带参构造")
10     {
11         cout << "执行了 Father 的构造函数" << endl;
12         int len = strlen(addr) + 1;
13         this->addr = new char[len];
14         strcpy_s(this->addr, len, addr);
15     }
16 
17     virtual ~Father()
18     {
19         cout << "执行了 Father 的析构函数" << endl;
20         if (this->addr)
21         {
22             delete addr;
23             addr = NULL;
24         }
25     }
26 private:
27     char *addr;
28 };
29 
30 
31 class Son :public Father
32 {
33 public:
34     Son(const char *game = "Son 带参构造", const char *addr = "继承 Father 带参构造" ) :Father(addr)
35     //Son(const char* game = "Son 带参构造")
36     {
37         cout << "执行了 Son 的构造函数" << endl;
38         int len = strlen(game) + 1;
39         this->game = new char[len];
40         strcpy_s(this->game, len, game);
41     }
42     ~Son()
43     {
44         cout << "执行了 Son 的析构函数" << endl;
45         if (this->game)
46         {
47             delete game;
48             game = NULL;
49         }
50     }
51 
52 private:
53     char* game;
54 };
55 
56 int main()
57 {
58     cout << "--------case 1----------" <<endl;
59     Father* father = new Father();
60     delete father;
61 
62     cout << "\n--------case 2----------" << endl;
63     Son* son = new Son();
64     delete son;
65 
66     cout << "\n--------case 3----------" << endl;
67     father = new Son();
68     delete father;
69 
70     return 0;
71 }

打印结果:

申请的内存均正确的释放。

扫描二维码关注公众号,回复: 10361418 查看本文章

结论:当我们把父类的析构函数定义为虚函数,这种修饰不是为了重写,他会让 Father 类(基类)的指针进行 Delete 操作时使用动态析构(如果这个指针指向的是子类对象,那么会先调用该子类的析构函数,然后在调用自己类的析构函数)。

养成习惯:为了防止内存泄漏,最好是在基类的析构函数上添加关键字 virtual ,使基类析构函数为虚函数。

======================================================================================================================

猜你喜欢

转载自www.cnblogs.com/CooCoChoco/p/12610015.html