C++多态之析构和纯虚析构分析与示例
C++ 分析 示例 多态
2023-06-13 09:11:02 时间
虚析构和纯虚析构
多态使用时,如果子类中有属性开辟到堆区,那么父类指针在释放时无法调用到子类的析构代码
解决方式:将父类中的析构函数改为虚析构或者纯虚析构
虚析构和纯虚析构共性:
- 可以解决父类指针释放子类对象
- 都需要有具体的函数实现
虚析构和纯虚析构区别:
- 如果是纯虚析构,该类属于抽象类,无法实例化对象
虚析构语法:
virtual ~类名(){}
纯虚析构语法:
virtual ~类名() = 0;
类名::~类名(){}
示例:
class Animal {
public:
Animal()
{
cout << "Animal 构造函数调用!" << endl;
}
virtual void Speak() = 0;
~Animal()
{
cout << "Animal虚析构函数调用!" << endl;
}
};
class Cat : public Animal {
public:
Cat(string name)
{
cout << "Cat构造函数调用!" << endl;
m_Name = new string(name);
}
virtual void Speak()
{
cout << *m_Name << "小猫在说话!" << endl;
}
~Cat()
{
cout << "Cat析构函数调用!" << endl;
if (this->m_Name != NULL) {
delete m_Name;//清除指针指向的堆区数据
m_Name = NULL;//指针为空
}
}
public:
string *m_Name;
};
void test01()
{
Animal *animal = new Cat("Tom");
animal->Speak();
delete animal;
}
int main() {
test01();
system("pause");
return 0;
}
上述案例输出:
发现没有调用cat的析构函数,即堆区的内存没有被释放,内存泄漏。
问题产生原因:因为是用的父类的指针指向的子类对象Animal *animal = new Cat("Tom");
所以当用delete父类指针时不会走子类的析构,导致子类如果有堆区的数据会出现内存的泄露情况。
通过父类指针去释放,会导致子类对象可能清理不干净,造成内存泄漏 怎么解决?给基类增加一个虚析构函数 虚析构函数就是用来解决通过父类指针释放子类对象时不干净的问题
class Animal {
public:
Animal()
{
cout << "Animal 构造函数调用!" << endl;
}
virtual void Speak() = 0;
//析构函数加上virtual关键字,变成虚析构函数
virtual ~Animal()//虚析构函数就是用来解决通过父类指针释放子类对象时不干净的问题
{
cout << "Animal虚析构函数调用!" << endl;
}
};
若使用纯虚析构时也可以解决
若是直接改成纯虚析构会报错
class Animal {
public:
Animal()
{
cout << "Animal 构造函数调用!" << endl;
}
virtual void Speak() = 0;
//析构函数加上virtual关键字,变成虚析构函数
virtual ~Animal() = 0;
};
语法强制纯虚析构函数必须有函数实现,因为有时父类也有一些数据开辟在堆区,既要使用纯虚函数,又要释放父类在堆区中的数据,就需要使用类内纯虚函数声明,类外写实现的写法。
注意:区别于纯虚函数可以只写声明不写实现,纯虚析构需要声明也需要实现。有了纯虚析构后,这个类也属于抽象类,无法实例化对象。
class Animal {
public:
Animal()
{
cout << "Animal 构造函数调用!" << endl;
}
virtual void Speak() = 0;
virtual ~Animal() = 0;
};
Animal::~Animal()
{
cout << "Animal 纯虚析构函数调用!" << endl;
}
//和包含普通纯虚函数的类一样,包含了纯虚析构函数的类也是一个抽象类。不能够被实例化。
class Cat : public Animal {
public:
Cat(string name)
{
cout << "Cat构造函数调用!" << endl;
m_Name = new string(name);
}
virtual void Speak()
{
cout << *m_Name << "小猫在说话!" << endl;
}
~Cat()
{
cout << "Cat析构函数调用!" << endl;
if (this->m_Name != NULL) {
delete m_Name;//清除指针指向的堆区数据
m_Name = NULL;//指针为空
}
}
public:
string *m_Name;
};
void test01()
{
Animal *animal = new Cat("Tom");
animal->Speak();
//通过父类指针去释放,会导致子类对象可能清理不干净,造成内存泄漏
//怎么解决?给基类增加一个虚析构函数
//虚析构函数就是用来解决通过父类指针释放子类对象
delete animal;
}
int main() {
test01();
system("pause");
return 0;
}
由于本案例在一些子类中有些数据开辟到堆区了,所以必须要走子类中的析构代码,如果使用了多态就走不到了,所以需要加上虚析构或者纯虚析构。
总结:
1. 虚析构或纯虚析构就是用来解决通过父类指针释放子类对象
2. 如果子类中没有堆区数据,可以不写为虚析构或纯虚析构
3. 拥有纯虚析构函数的类也属于抽象类
相关文章
- c++语言截取字符串,详解C++ string常用截取字符串方法
- C++ 类访问修饰符
- C++中string append函数的使用与字符串拼接「建议收藏」
- c++ auto类型_auto C++
- C++异常的介绍和分析
- c++11面试宝典(final,delete,deault,explicit,lambda表达式)
- C++关键知识点梳理
- C/C++ 反汇编:数据类型与常量
- 【C++修炼之路】19.AVL树
- c++基础篇之C++ 模板
- 【C++】哈希的应用 -- 布隆过滤器
- C++中的类继承之单继承&多继承&菱形继承详解编程语言
- C++格式化输出(详解版)
- C++创建桌面快捷方式开始菜单的实现代码
- C++中四种对象生存期和作用域以及static的用法总结分析
- 探讨register关键字在c语言和c++中的差异
- 筛选法的C++实现
- C++获取本机登陆过的QQ号码示例程序
- C++基础入门教程(一):基础知识大杂烩
- C++空类及没有成员变量的类的大小实例分析
- C++虚函数的实现机制分析
- C++快速排序的分析与优化详解
- C++多重继承和虚拟继承对象模型、效率分析
- C++实现不能被继承的类实例分析
- C++编译器无法捕捉到的8种错误实例分析
- C++虚函数表实例分析
- C/C++中extern"C"的作用分析