C++语法|虚函数与多态详细讲解(四)|哪些函数不能实现成虚函数和虚析构函数的理解

系列汇总讲解,请移步:
C++语法|虚函数与多态详细讲解系列(包含多重继承内容)

文章目录

  • 哪些函数不能成为虚函数
  • 虚析构函数
    • 什么时候把基类的析构函数必须是线程虚函数

哪些函数不能成为虚函数

要回答这个问题,首先我们要明确虚函数到底依赖于什么?

虚函数的依赖:

  1. 虚函数能产生函数地址,存储在vftable当中
  2. 虚函数表的地址在虚函数指针中存储吗所以我们要有vfptr。
  3. vfptr在对象的内存中存储。

所以说,虚函数本质上,是依赖于类实例化后的对象内存的

所以我们可以得出两类函数不能成为虚函数:

  • 构造函数不能是虚函数

    • 类的实例化对象只有在构造函数执行之后才有相应的内存。
    • 构造函数中调用的任何函数,都是静态绑定的,也就是说,构造函数中调用虚函数,也不会发生动态绑定。
      • 派生类对象构造过程,1. 先调用的是基类的构造函数;2.才调用派生类的构造函数,所以在构造函数中是不会发生动态绑定的
  • static静态成员方法也不能是虚函数,

    • 静态成员方法根本就不依赖于对象,我们要写成虚函数就要把其地址写到虚函数表当中,但是我对象都还没实例化呢!哪来的虚函数表呢?

听完以上讲解,你觉得析构函数可以是虚函数吗?

虚析构函数

析构函数调用的时候,对象是存在的!所以按道理来说析构函数也可以是虚函数,接下来我将论述有些情况下析构函数必须得设置成虚函数的必要性。

我们一起看以下案例:
设置类:

class Base {
public:Base(int data = 10) : ma(data) { cout << "Base()" << endl; }~Base() { cout << "~Base()" << endl; }virtual void show() { cout << "Base::show()" << endl; }virtual void show(int) { cout << "Base::show(int)" << endl; }
protected:int ma;
};
class Derive : public Base {
public:Derive(int data = 20) : Base(data), mb(data) { cout << "Derive()" << endl;}~Derive() { cout << "~Derive()" << endl;}void show() {cout << "Derive::show()" << endl; }
private:int mb;
};

设置测试函数:

int main () {Base *pb = new Derive(10);pb->show();//动态绑定delete pb; //派生类的析构函数没有被调用到,其实这里就是静态绑定
}

我们首先打印pb->show(),最后析构pb指针。
我们会发现打印结果如下:

Base()
Derive()
Derive::show()
~Base()

首先我们new了一块Derive的堆内存,一次构造Base()和Derive()。
随后我们调用pd指向的show(),调用的是Derive::show(),这是由于该函数是动态绑定的。
最后我们释放pb的内存,竟然只析构了Base(),不析构Derive()!
这是为什么呢?

我们简单分析一下就知道,由于我们的指针是Base*类型,所以它的析构函数属于静态绑定,绑定的是Base的析构函数,所以我们在释放内存时,只调用了Base的析构函数。我们Derive的析构函数根本就没有条件调用 !

所以正确的写法应该是把Base()的析构函数改写成虚析构函数。那么对于派生类而言,既然基类的析构函是virtual虚函数,那么派生类的析构函数自动成为虚函数。

所以我们在调用:

delete pb;

这是一个动态绑定,调用的是Derive类的析构函数。

我们再来看最终的结果:

Base()
Derive()
Derive::show()
~Derive()
~Base()

所以打印结果是能够析构Derive(),然后由于其基类是Base,后续会调用Base的析构函数。

完美释放Derive的资源!

什么时候把基类的析构函数必须是线程虚函数

基类的指针(引用)指向堆上new出来的派生类对象的时候,delete pb(基类的指针),他调用析构函数的时候,必须发生动态绑定,不然会导致派生类的析构函数无法被调用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/17950.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何取消公众号的在线客服绑定授权

1&#xff0c;功能设置 2&#xff0c;公众号设置 3&#xff0c;查看详情&#xff0c;取消

开发远程遥控情趣玩具软件,提供现成程序源码应具备哪些基础功能

以“东莞梦情智能”为参考&#xff0c;其提供的现成情趣玩具遥控软件程序源码&#xff0c;所具备哪些基础功能&#xff0c;看看它们如何让情趣玩具变得更加丰富多彩。 一、设备连接 设备连接是情趣玩具遥控软件的基础功能之一。“东莞梦情智能”的现成源码支持多种连接方式&am…

leetcode题目42

接雨水 困难 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1] 输出&#xff1a;6 解释&#xff1a;上面是由数组 [0,1,0,2,1,0,1…

mysql中text,longtext,mediumtext区别

文章目录 一.概览二、字节限制不同三、I/O 不同四、行迁移不同 一.概览 在 MySQL 中&#xff0c;text、mediumtext 和 longtext 都是用来存储大量文本数据的数据类型。 TEXT&#xff1a;TEXT 数据类型可以用来存储最大长度为 65,535(2^16-1)个字符的文本数据。如果存储的数据…

开源VS闭源:谁更能推动AI技术的普及与发展?

一、引言 在人工智能&#xff08;AI&#xff09;技术的浪潮中&#xff0c;开源与闭源两种模式一直并存&#xff0c;并各自在推动AI技术普及与发展上发挥着重要作用。然而&#xff0c;关于哪种模式更能有效地推动AI技术的普及与发展&#xff0c;一直存在着激烈的讨论。本文将深…

Bitmap 的基本原理

Bitmap 是一种用于表示数据的高效方法&#xff0c;特别适合在需要表示大量布尔值&#xff08;true 或 false&#xff09;的情况下使用。它的原理是使用二进制位来表示每一个布尔值&#xff0c;节省了存储空间和操作时间。 Bitmap 的基本原理 想象一下&#xff0c;你有一个很长…

树莓派指令

1.常用指令 2.在终端窗口编辑文本文件 2.1nano编辑器 在文本里ctrlG就可以查看更多的快捷按键 2.2vi编辑器 进入默认为命令模式

Python2没有模板字符串用法吗?

Python2中也有模板字符串的使用方式&#xff0c;使用的是string.Template模块&#xff0c;可以通过构造一个Template对象来实现。不过在Python3中&#xff0c;模板字符串被引入为一种更加方便的语法&#xff0c;直接在字符串中使用大括号{}来表示占位符&#xff0c;可以更加简洁…

百川股份:大王蹲完,小王蹲

一根大阴线&#xff0c;正丹股份的十倍股传奇之旅即将落幕&#xff1f; 有股民表示&#xff1a;化工板块还有高手&#xff0c;大王倒了还有小王。 今天我们聊的正是化工板块被称为“正丹第二”的百川股份。 虽难比正丹的十倍涨幅&#xff0c;但百川也不简单&#xff0c;3个月…

视频号小店是怎么操作的?适用于所有人的操作玩法!

大家好&#xff0c;我是电商小V 视频号小店是怎么操作的呢&#xff1f;这是刚开始去做&#xff0c;或者是刚了解的小伙伴最疑惑的问题&#xff0c; 视频号小店是22年推出的&#xff0c;也是目前最火的一个创业型项目&#xff0c;也是吸引了不少的商家入驻&#xff0c;今天咱们就…

微服务架构的优势 与 不足

优势 微服务架构是一种将应用程序作为一套小服务的集合来开发和部署的方法&#xff0c;每个服务运行在其独立的进程中&#xff0c;并通常围绕业务能力组织。服务之间通过定义良好的API进行通信。微服务架构的优势包括&#xff1a; 1. 独立部署 每个微服务可以独立部署到生产…

自动化技术-图像识别

白屏检测:使用OpenCV来判断,首先通过pyautogui库获取屏幕截图,然后将其转成灰度图像,接着计算灰度图像的平均值,如果平均值大于阈值则为白屏 import cv2 import numpy as np import pyautogui# 获取屏幕截图 screenshot = pyautogui.screenshot() screenshot = np.array(s…

PLC远程调试

随着工业自动化的快速发展&#xff0c;PLC&#xff08;可编程逻辑控制器&#xff09;已经成为现代工业生产线的核心控制设备。然而&#xff0c;传统的PLC调试方式往往受限于地理位置和物理连接&#xff0c;使得工程师在调试过程中面临诸多不便。在这个背景下&#xff0c;HiWoo …

OpenHarmony 实战开发——内核对象队列之算法详解

前言 OpenAtom OpenHarmony&#xff08;以下简称“OpenHarmony”&#xff09; LiteOS-M 内核是面向 IoT 领域构建的轻量级物联网操作系统内核&#xff0c;具有小体积、低功耗、高性能的特点。在嵌入式领域的开发工作中&#xff0c;无论是自研还是移植系统&#xff0c;均绕不开…

Pytorch-07 完整训练测试过程

要在PyTorch中使用GPU进行数据集的加载、模型的训练和最后模型的测试&#xff0c;需要将数据集和模型都移动到GPU上&#xff0c;并确保在训练和测试过程中都在GPU上进行计算。以下是一个完整的示例代码&#xff0c;展示了如何在PyTorch中使用GPU进行端到端的训练和测试&#xf…

六月后考研如何备考看这一篇就够了

以下是考研六月后可以参考的规划&#xff1a; 6 月至 8 月&#xff08;强化阶段&#xff09;&#xff1a; 英语&#xff1a;继续背单词&#xff0c;开始刷历年真题中的阅读部分&#xff0c;仔细分析错题原因&#xff0c;总结解题技巧。数学&#xff1a;完成基础阶段的复习后&am…

接口作为返回类型与类作为返回类型一样吗?

LinkedList<Integer> q new LinkedList<>();和Queue<Integer> q new LinkedList<>();一样吗&#xff1f; 我现在想创建一个队列对象&#xff0c;正常情况下我会这样写&#xff1a;Queue<Integer> q new Queue<>(); 但是你仔细想想&am…

使用chatglm.cpp本地部署ChatGLM3-6B模型

ChatGLM3模型介绍 ChatGLM3-6B 是 ChatGLM 系列最新一代的开源模型&#xff0c;在保留了前两代模型对话流畅、部署门槛低等众多优秀特性的基础上&#xff0c;ChatGLM3-6B 引入了如下特性&#xff1a; 更强大的基础模型&#xff1a; ChatGLM3-6B 的基础模型 ChatGLM3-6B-Base …

Yourpassword does not satisfy the current policyrequirements

mysql 新增数据库用户失败 解决方法&#xff1a; 修改校验密码策略等级 set global validate_password.policyLOW;

dataguard 备库关闭后启动流程

startup mount&#xff1b; ---开启adg alter database recover managed standby database using current logfile disconnect from session; -- alter database recover managed standby database cancel; alter database recover managed standby database disconnect…