结论:
实现多态时,我们通过基类指针指向子类对象,在delete基类指针时,我们希望先调用子类的析构函数,再调用父类的析构函数,要实现这个目的,析构函数就必须定义成虚函数,否则只会调用父类的析构函数,子类的析构函数不会被调用。
实验1:析构函数不定义成虚函数
#include <iostream> using namespace std; class father { public: father(int num) { cout << "create father" << endl; // new申请的内存不用判空,new不到内存会抛出异常,不会返回空指针 father_ptr = new int(num); } ~father() { cout << "destory father" << endl; if (father_ptr != nullptr) { delete father_ptr; } // 释放内存以后,一定记得置空,防止出现野指针 father_ptr = nullptr; } private: int *father_ptr; }; class child : public father { public: // 父类没有无参构造函数,需要显示调用父类构造函数 child(int x, int y) : father(x) { cout << "create child" << endl; child_ptr = new int(y); } ~child() { cout << "destory child" << endl; if (child_ptr != nullptr) { delete child_ptr; } child_ptr = nullptr; } private: int *child_ptr; }; int main() { father *ptr = new child(10, 20); delete(ptr); return 0; }
运行结果:结果说明不定义成虚函数,只会调用父类的析构函数,不会调用子类的析构函数,导致内存泄露。
实验2:析构函数定义成虚函数
#include <iostream> using namespace std; class father { public: father(int num) { cout << "create father" << endl; // new申请的内存不用判空,new不到内存会抛出异常,不会返回空指针 father_ptr = new int(num); } virtual ~father() { cout << "destory father" << endl; if (father_ptr != nullptr) { delete father_ptr; } // 释放内存以后,一定记得置空,防止出现野指针 father_ptr = nullptr; } private: int *father_ptr; }; class child : public father { public: // 父类没有无参构造函数,需要显示调用父类构造函数 child(int x, int y) : father(x) { cout << "create child" << endl; child_ptr = new int(y); } virtual ~child() { cout << "destory child" << endl; if (child_ptr != nullptr) { delete child_ptr; } child_ptr = nullptr; } private: int *child_ptr; }; int main() { father *ptr = new child(10, 20); delete(ptr); return 0; }
运行结果:父类和子类都正常析构了。
tips:良好的编程习惯,不管类中有没有指针,有没有动态申请内存,都应该把析构函数定义成虚函数,定义成虚函数总是不会错的。