C++ 消失的析构函数 —— virtual 实现的动态析构
阅读原文时间:2023年07月08日阅读:1

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

1 #include
2 #include
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
2 #include
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 }

打印结果:

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

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

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

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

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章