C++ 为什么基类的析构函数要声明为虚函数

2023-05-16

1、为什么声明基类析构函数为虚函数?
(1)基类指针 指向 基类对象:不用考虑基类析构函数是否声明为虚函数。
(2)基类指针 指向 派生类对象:若基类析构函数不为虚函数,在delete基类指针时,只会调用基类的析构函数,不会调用派生类的析构函数(资源未释放,基类无法操作派生类中非继承的成员),进而可能导致内存泄漏。

2、如下代码示例

#include<iostream>
using namespace std;

//基类A
class classA
{
public:
	classA(){ cout << "Construct in classA" << endl; };

	~classA(){ cout << "Destruct in classA" << endl; };

	void print(){ cout << "Print classA" << endl; };
};
//派生类B
class classB : public classA
{
public:
	classB(){ cout << "Construct in classB" << endl; };

	~classB(){ cout << "Destruct in classB" << endl; };

	void print(){ cout << "Print classB" << endl; };
};

//基类C
class classC
{
public:
	classC(){ cout << "Construct in classC" << endl; };

	//虚析构函数
	virtual ~classC(){ cout << "Destruct in classC" << endl; };

	//虚成员函数
	virtual void print(){ cout << "Print classC" << endl; };
};
//派生类D
class classD : public classC
{
public:
	classD(){ cout << "Construct in classD" << endl; };

	//以下两个函数可不加virtual关键字修饰,由于函数重写编译时会默认加上(基类C中为虚函数)
	//析构函数比较特殊,编译时名字一样,因此也构成函数重写
	virtual ~classD(){ cout << "Destruct in classD" << endl; };

	virtual void print(){ cout << "Print classD" << endl; };
};

int main()
{
	cout << "------------part 1------------" << endl;
	classB *ptrB = new classB;//派生类指针指向派生类对象
	ptrB->print();
	delete ptrB;
	
	cout << endl << "------------part 2------------" << endl;
	classA *ptrA = new classB;//基类指针指向派生类对象(基类非虚析构)
	ptrA->print();
	delete ptrA;

	cout << endl << "------------part 3------------" << endl;
	classC *ptrC = new classD;//基类指针指向派生类对象(基类虚析构)
	ptrC->print();
	delete ptrC;

	cout << endl << "------------part 4------------" << endl;
	classC *ptrC1 = new classC;//基类指针指向基类对象
	ptrC1 ->print();
	delete ptrC1 ;

	getchar();
	return 0;
}

3、执行结果及分析
(1)执行结果
在这里插入图片描述
(2)分析
①part 1:派生类对象创建与销毁时,构造及析构函数的调用顺序为,基类构造→派生类构造→派生类析构→基类析构。

②part 2:基类A析构函数不为虚函数,delete基类指针时,未调用派生类B析构函数(非多态,根据指针类型调用)。

③part 3:与part 2对比(上图中红色标记),基类C中析构函数为虚函数,此时形成多态(与类型无关,只与对象有关),delete基类指针时,先调用派生类的析构函数,后调用基类的析构函数。

④part 4:与part 3对比(Print函数输出),基类指针指向基类对象时,调用基类的成员函数;指向派生类对象时,调用派生类的成员函数。这便是多态(动态绑定),在程序执行过程中,动态决定调用哪个函数。

4、多态介绍
多态(动态绑定)的核心是虚函数、虚表、虚表指针,此处推荐一篇头条上的文章《C++ 虚函数表剖析》,链接:C++ 虚函数表剖析。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++ 为什么基类的析构函数要声明为虚函数 的相关文章

随机推荐

  • nginx负载均衡 upstream ip_hash的用法

    文章目录 场景参考文档用法 场景 负载均衡解决session共享的问题 参考文档 nginx org upstream 用法 语法 Syntax ip hash Default Context upstream 说明 Specifies t
  • ros 播放激光雷达数据包,rviz可视化

    通过bag文件记录话题消息 当发布话题的节点运行后 xff0c 可以通过rostopic list 列出当前 运行的话题 xff0c 然后记录 xff1a mkdir bagfile cd bagfile rosbag record a 记
  • TIM2_CH1_ETR可以当做TIM2_CH1来用

    TIM2 CH1 ETR可以当做TIM2 CH1来用 在stm32中文参考手册8 3 7定时器复用功能重映射小节可以看到这样的描述
  • hal库LTDC的层数判断应为<而不是<=

    LTDC的层数判断为 IS LTDC LAYER LAYER LAYER lt 61 MAX LAYER 假设MAX LAYER 61 2 xff0c 则LAYER等于2时也满足条件判断 但在配置寄存器时 xff0c 寄存器的地址依靠 la
  • 【无标题】

    hal库 SD卡总线宽度设置8不支持 xff0c 但还是保留了设置总线宽度为8的宏定义 HAL SD ErrorTypedef span class token function HAL SD WideBusOperation Config
  • 【无标题】

    发现一个问题 使用HAL库中的这个类型定义变量 xff0c 但不使用的话居然不会报警告 就是它 xff1a DMA HandleTypeDef
  • 【无标题】

    勘误 xff1a stm32F4xx参考手册中 34 11小节FIFO框架图中 最上面的DIEPTXF2 31 16 应为DIEPTXFn 31 16
  • HttpURLConnection高阶使用之kerberos认证解决方案

    1 HttpURLConnection 简介 sun net www protocol http HttpURLConnection是jdk中默认执行请求时使用 此HttpURLConnection 支持多种权限认证方案 xff0c Neg
  • 下篇 | 开发板AMR接收虚拟机Ubuntu传来的文件

    上篇笔记 xff1a 虚拟机Ubuntu向开发板AMR传送文件 已经做好了虚拟机向开发板传送文件的笔记啦 xff0c 然后有发送肯定有接收的 xff0c 不然就发空气啦 xff01 接下来 xff0c 写开发板如何接受虚拟机发送过来的文件的
  • 解决QT->setText()中文出现乱码问题,使用QString或者tr()均出现乱码。

    微软VC编译器源代码使用GB2312编码进行保存 源码中的汉字字符串在生成可执行文件的过程中被转换成了本地编码 Qt内部是使用Unicode编码 xff0c 即QString保存的是Unicode编码的字符串 Qt内部需要使用Unicode
  • Qt 下载图片并显示图片

    源码下载 xff1a 图片下载器 include 34 mainwindow h 34 include 34 ui mainwindow h 34 include lt QHostAddress gt include lt QDebug g
  • 海康威视 web3.0开发 常见错误 404,403

    海康威视 web3 0开发 常见错误 404 xff0c 403 配置情况 IE 浏览器 43 nginx 43 thinkPHP5 0 43 海康威视200万星光级红外球机1080P变焦云台球机DS 2DC4223IW D 关于如何使用网
  • 虚拟USB设备总结

    开发环境 xff1a windows 首先来总结最近研究的虚拟USB设备 xff0c 进而虚拟USB键盘成功了 xff0c 开心 xff01 得出了一个C S框架 xff0c 首先说一下客户端 客户端有两个部分 xff0c 用户空间工具和底
  • C#Winform:《DataGridViewComboBoxCell值无效》解决方案

    值无效 xff0c 可能是你下拉框选项 xff0c 没有这样的值 xff0c 而你却设置这个值 dataGridView1 Rows i Cells 1 Value 61 Hello World 解决方法就是在窗体的构造函数里添加如下代码
  • FFmpeg笔记

    1 下载 xff0c 配置 FFmpeg官网 xff1a https ffmpeg org 用的系统是Ubuntu18 04 所以直接apt get就可以了 sudo apt get install ffmpeg 2 简介 xff0c 上手
  • 《WPF中TextBox绑定Double类型数据,文本框不能输入小数点》解决方案

    在App cs文件里面 xff0c 重写OnStatup xff0c 添加下面一条语句即可 span class token keyword public span span class token keyword partial span
  • stm32 HAL库串口收发-中断接收DMA发送不定长数据

    使用的时候发现 xff1a 接收完一个字节立即用DMA的方式发送出去 xff0c 会出现数据的丢失 xff0c 如用串口调试助手发送1234 xff0c 返回的只有13 目前只能用缓存buf 43 协议结束 xff08 如0x0d 0x0a
  • headers Authorization

    var auth 61 96 host user host pass 96 const buf 61 Buffer from auth 39 ascii 39 strauth 61 buf toString 39 base64 39 con
  • 平衡车入门---MPU6050陀螺仪的使用

    平衡车入门 MPU6050陀螺仪的使用 一 MPU6050简介二 学习MPU6050的步骤三 I2C协议简介四 MPU6050硬件介绍五 MPU6050的几个重要寄存器六 原始数据的单位换算七 角度换算 滤波算法 一 MPU6050简介 M
  • C++ 为什么基类的析构函数要声明为虚函数

    1 为什么声明基类析构函数为虚函数 xff1f xff08 1 xff09 基类指针 指向 基类对象 xff1a 不用考虑基类析构函数是否声明为虚函数 xff08 2 xff09 基类指针 指向 派生类对象 xff1a 若基类析构函数不为虚