在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 }
打印结果:
申请的内存均正确的释放。
结论:当我们把父类的析构函数定义为虚函数,这种修饰不是为了重写,他会让 Father 类(基类)的指针进行 Delete 操作时使用动态析构(如果这个指针指向的是子类对象,那么会先调用该子类的析构函数,然后在调用自己类的析构函数)。
养成习惯:为了防止内存泄漏,最好是在基类的析构函数上添加关键字 virtual ,使基类析构函数为虚函数。
======================================================================================================================