多态使用时,如果子类有对象开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码
解决方式:将父类中的析构函数改为虚析构或者春虚析构
虚析构和纯虚析构的共性:
- 可以解决父类指针释放子类对象
- 都需要有具体的函数实现
虚析构和纯虚析构的区别:
- 如果是纯虚析构,该类属于抽象类,无法实例化对象
虚析构语法:
virtual ~类名(){}
纯虚析构语法:
virtual ~类名()=0; 类名::类名(){};
常规操作:
#include<iostream> using namespace std; class animal { public: virtual void speak() = 0; }; class dog : public animal { public: void speak() { cout << "小狗在说话" << endl; } }; class cat : public animal { public: void speak() { cout << "小猫在说话" << endl; } }; void test01() { animal* it = new cat; it->speak(); delete it; } int main() { test01(); system("pause"); }
但是如果子类对象有开辟空间到堆区时,在子类中创建指针:
class cat : public animal { public: void speak() { cout << *m_name<<"小猫在说话" << endl; } cat(string name) { m_name =new string(name); } string* m_name; }; void test01() { animal* it = new cat("tom"); it->speak(); delete it; }
在父类子类对象中都打印一些字符会发现,子类的析构函数并没有调用,说明堆区并没有释放干净,这样就会造成内存泄露。
这是因为父类指针在析构时并不会调用子类的析构函数,导致子类如果有堆区对象,就会造成内存泄露。
cat类中有堆区属性,应该在该子类中将其释放,解决这个问就就需要虚析构
虚析构的语法就是在父类析构函数前加上一个virtual关键字,结果:
子类的析构函数已调用。
以上就是利用父类指针解决子类对象时释放不干净的问题
纯虚析构
纯虚析构需要有什声明,也需要有具体 的实现;
有了纯虚析构后这个类也属于抽象类,无法实例化对象;
#include<iostream> #include<string> using namespace std; class animal { public: animal() { cout << "animal构造函数已调用" << endl; } //virtual ~animal() //虚析构 虚析构与纯虚析构只能存在一个 //{ // cout << "animal析造函数已调用" << endl; //} virtual ~animal() = 0; //纯虚析构声明 virtual void speak() = 0; }; animal::~animal() //纯虚析构具体实现 { cout << "animal纯虚析构已调用" << endl; }; class dog : public animal { public: void speak() { cout << "小狗在说话" << endl; } }; class cat : public animal { public: void speak() { cout << *m_name<<"小猫在说话" << endl; } cat(string name) { cout << "cat构造函数已调用" << endl; m_name =new string(name); } ~cat() { if (m_name != NULL) { cout << "cat析构函数已调用" << endl; delete m_name; m_name = NULL; } } string* m_name; }; void test01() { animal* it = new cat("tom"); it->speak(); delete it; } int main() { test01(); system("pause"); }