C++Note 虚析构和纯虚析构
多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码
解决方式:将父类中的析构函数改为虚析构或者纯虚析构
虚析构和纯虚析构共性:
可以解决父类指针释放子类对象
都需要有具体的函数实现
虚析构和纯虚析构区别:
如果是纯虚析构,该类属于抽象类,无法实例化对象
虚析构语法:
virtual ~类名(){}
纯虚析构语法:
virtual ~类名() = 0;//类内纯虚构
类名::类名(){}//作用域 + 类名
虚析构之前:
1 class Animal 2 { 3 public: 4 Animal() 5 { 6 cout << "Animal的构造函数调用" << endl; 7 } 8 ~Animal() 9 { 10 cout << "Animal的析构函数调用" << endl; 11 } 12 virtual void speak() = 0; 13 14 }; 15 class Cat :public Animal 16 { 17 public: 18 Cat(string name) 19 { 20 cout << "Cat的构造函数调用" << endl; 21 m_Name = new string(name); 22 } 23 virtual void speak() 24 { 25 cout << *m_Name <<"猫叫" << endl; 26 } 27 ~Cat() 28 { 29 if (m_Name != NULL) 30 { 31 cout << "Cat的析构函数调用" << endl; 32 delete m_Name; 33 m_Name = NULL; 34 } 35 } 36 string* m_Name; 37 }; 38 void test() 39 { 40 Animal* animal = new Cat("Tim"); 41 animal->speak(); 42 //父类指针在析构时候,不会调用子类中析构函数,导致子类如果有堆区属性,出现内存泄露 43 delete animal; 44 }
输出:
虚析构之后:
1 class Animal 2 { 3 public: 4 Animal() 5 { 6 cout << "Animal的构造函数调用" << endl; 7 } 8 //利用虚析构可以解决 父类指针释放自类对象时不干净的问题 9 virtual ~Animal() 10 { 11 cout << "Animal的析构函数调用" << endl; 12 } 13 virtual void speak() = 0; 14 };
结果输出:
纯虚析构:
1 class Animal 2 { 3 public: 4 Animal() 5 { 6 cout << "Animal的构造函数调用" << endl; 7 } 8 virtual ~Animal() = 0;//纯虚析构 9 virtual void speak() = 0; 10 };
但是此时报错:无法解析的外部命令( 链接阶段报错) 预处理、编译、汇编、链接
此时纯虚析构只是一个声明,无代码实现,但析构函数有执行,(父类中也可能也有数据开辟到堆区,此时父类中析构函数实现起到作用)
虚析构 或 纯虚析构都需要代码实现
1 class Animal 2 { 3 public: 4 Animal() 5 { 6 cout << "Animal的构造函数调用" << endl; 7 } 8 virtual ~Animal() = 0;//纯虚析构 需要声明 也需要实现 9 virtual void speak() = 0; 10 }; 11 Animal::~Animal() 12 { 13 cout << "Animal的析构函数调用" << endl; 14 }
总结:
1.虚析构或纯虚析构就是用来解决通过父类指针释放子类对象
2.如果子类中没有堆区数据,可以不写为虚析构或纯虚析构
3.拥有纯虚析构函数的类也属于抽象类
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)