C++(虚构造与虚析构/类型信息运算符/强制类型转换)
一、虚构造与虚析构
1、构造函数能否是虚函数,为什么?
对象有创建过程:
1、给对象分配内存
2、根据继承表顺序调用父类构造
3、根据成员对象的的定义顺序调用成员对象的构造函数
4、执行对象自己的构造函数
如果父类的构造函数函数设计成虚函数并且被子类覆盖(如果虚函数没有被覆盖就设计的没有意义),当创建子类对象时,先调用父类的虚构造,但此时实际对象是子类对象,根据多态的特性此时会转而执行子类的构造(调用虚函数表中覆盖后的版本),但执行子类构造函数前需要先执行父类构造,这样就形成了死循环,所以构造函数不能设计成虚函数。
#include <iostream> using namespace std; class Base { public:// error: constructors cannot be declared virtual [-fpermissive] virtual Base(void)virtual Base(void){cout << "Base构造函数" << endl;} }; class Test: public Base { public:Test(void){cout << "Test构造函数" << endl;} }; int main(int argc,const char* argv[]) {return 0; }
2、析构函数能否是虚函数,为什么?
对象的释放过程:
1、执行对象自己的析构函数
2、根据成员对象的创建过程逆序执行成员对象的析构函数
3、根据继承表的顺序逆序执行父类的析构函数
4、释放对象的内存
假如父类的析构函数设计成虚函数并且被子类覆盖,当释放子类对象时,先执行子类对象的析构函数,然后执行父类对象的析构函数,此时子类对象已经被释放完毕,所以无法形成多态,只会执行父类的析构函数,不会产生任何错误,所以析构函数可以是虚函数。
3、什么情况需要设计虚析构
当使用类多态时,使用父类指针、引用去释放子类对象时,如果析构函数没有设计成虚函数(没有覆盖),那么将只执行父类的析构函数(无法调用子类的析构函数),如果子类中有指针成员且指向堆内存,这种情况下就会造成内存泄漏。
注意:当使用类多态时,且子类成员中有指针指向堆内存,必须要把父类的析构函数设计成虚函数(或者子类的析构函数中有必须要完成的工作时)。
#include <iostream> using namespace std; class Base { public:Base(void){cout << "Base的构造函数" << endl;}virtual ~Base(void){cout << "Base的析构函数" << endl;}virtual void func(void){cout << "我是Base类的func函数" << endl;} }; class Test : public Base {int* ptr; public:Test(void){ptr = new int;cout << "alloc" << ptr << endl;}~Test(void){delete ptr;cout << "free" << ptr << endl;}void func(void){cout << "我是Test类的func函数" << endl;} }; int main(int argc,const char* argv[]) {Base* x = new Test;x->func();delete x;return 0; }
总结:构造函数不能是虚函数,否则会形成死循环,析构函数可以设计成虚函数,在使用类多态时,如果不把析构函数设计成虚函数,则子类的析构不会被调用,也就说在使用类多态时,子类的析构函数想要执行,则需要把父类的析构设计成虚函数。
二、类型信息运算符
1、什么类型信息运算符
C++中有这个typeid关键字,用于获取数据的类型信息。
2、类型信息运算符的作用。
当我们使用类多态时,我们很难通过肉眼识别出对象的真实类型(特别是在使用工厂模式时),如果父子类形成了多态,使用typeid就可以获取到对象的真实类型。
以及判断是否函数,还是函数指针,判断标识符是否指针变量、是否是二级指针。
3、使用方法
1、需要包含头文件 #include <typeinfo> 并且它设计在std名字空间内。
2、typeid(数据) 会返回一个记录数据类型信息的type_info类型的类对象。
3、type_info 有一个name成员函数,会以字符串形式返回类型的名字:
1、基本类型返回类型的缩写
2、指针类型以P开头
3、带const属性的,名字中会带K
4、复合类型的会返回长度+名字
5、如果父类引用指向了子类对象,只要父类中定义的虚函数,typeid就可以识别出真实的对象类型。
6、如果父类指针指向了子类对象,父类中定义的虚函数,typeid(*指针)才可以识别出真实的对象类型。
4、type_info 有一些成员函数和运算符函数:
判断一个标识符是否是指针变量,__is_pointer_p() 判断一个标识符是否是函数, __is_function_p()
#include <typeinfo> using namespace std; struct Student { }; class Base { public:virtual void func(void){ } }; class Test : public Base { }; int main(int argc,const char* argv[]) {cout << typeid(char).name() << endl;cout << typeid(short).name() << endl;cout << typeid(int).name() << endl; Student s;cout << typeid(s).name() << endl; Test t;Base& b = t;cout << typeid(b).name() << endl; Base* p = new Test;cout << typeid(p).name() << endl;cout << typeid(*p).name() << endl; cout << typeid(main).__is_function_p() << endl;cout << typeid(p).__is_pointer_p() << endl; cout << (typeid(t) == typeid(b)) << endl;cout << (typeid(t) != typeid(b)) << endl; return 0; }
三、强制类型转换
C++语言为了兼容C语言,依然保留着C语言中的强制类型转换语法,但C语言中的强制类型转换有以下缺点:
1、任何类型之间都可以强制类型转换,所以使用起来比较随意,代码的阅读性性差。
2、不会对原数据和目标类型检查,程序员需要对转换的结果负责(可能会出现数据丢失、段错误等问题)。
基于以上原因C++之父在C++中提供一套更安全的强制类型转换,并且C++之父认为好的代码设计不应该会使用到强制类型转换,当程序需要使用强制类型转换时,就说明你的代码设计有问题,程序不应该使用强制类型转换而是应该重新修改代码的设计,所以强制类型转换的语法设计的难以记忆。
1、去常类型转换
const_cast<目标类型>(源数据)
源数据和目标类型之间除了const属性不同,其它没有任何区别,否则就会产生编译错误,一般用于去掉指针或引用的常属性。
2、静态类型转换
static_cast<目标类型>(源数据)
源数据和目标类型之间必须有一个方向能自动类型转换,否则就会产生编译错误,一般使用在大字节数的数据转换成小字节数的数据。
3、重解释类型转换
reinterpret_cast<目标类型>(数据)
专用于指针变量的类型转换,主要用于指针与指针的转换,指针与整数的转换,与其它的强制类型转换相比,它的自由度比较高,但也比较危险。
4、动态类型转换
dynamic_cast<目标类型> (数据)
把父类的指针或引用转换成子类的指针或引用,并且父类中必须有虚函数表指针。
相关文章:
C++(虚构造与虚析构/类型信息运算符/强制类型转换)
一、虚构造与虚析构 1、构造函数能否是虚函数,为什么? 对象有创建过程: 1、给对象分配内存 2、根据继承表顺序调用父类构造 3、根据成员对象的的定义顺序调用成员对象的构造函数 4、执行对象自己的构造函数 如果父类的构造函数函数设计…...

python毕业设计基于django+vue医院社区医疗挂号预约综合管理系统7918h-pycharm-flask
目录 技术栈和环境说明预期达到的目标具体实现截图系统设计Python技术介绍django框架介绍flask框架介绍解决的思路性能/安全/负载方面可行性分析论证python-flask核心代码部分展示python-django核心代码部分展示操作可行性技术路线感恩大学老师和同学详细视频演示源码获取 技术…...

tidb 集群搭建
官网的搭建文档:使用 TiUP 部署 TiDB 集群 | TiDB 文档中心 我本地使用三台 centos7.9 服务器搭建,要保证三台服务器之间是可以互相通信的; 搭建集群的命令在其中一台服务器上执行即可; 1、安装tiup: curl --proto …...
SpringBoot开发——Spring Boot Controller 最佳实践
文章目录 1、RESTful接口地址的定义规则2、设计通用控制器基类3、统一的返回对象设计4、统一的异常处理5、实际案例: 订单控制器 (OrderController)结论 随着微服务架构的普及,RESTful API已经成为现代Web服务的标准设计模式。Spring Boot为开发者提供了强大的工具来…...

使用Ubuntu耳机输出正弦波信号
最近有一个项目想使用喇叭发出一个标准的正弦波测试信号,故记录下操作过程 sudo apt install libasound2-dev 否则有可能会报错: alsaaudio.c:28:10: fatal error: alsa/asoundlib.h: No such file or directory 安装pyalsaaudio: pip …...
Python编程 - 协程
前言 上篇文章主要讲述了python的进程,进程池和进程与线程对比等知识,接下来这篇文章再唠唠python的协程,让我们继续往下看! 一、协程的使用 python 中的协程是一种用于处理并发任务的高效工具,它依赖于 asyncio 库以…...

如何在没有备份的情况下恢复 Mac 上丢失的数据
Mac 是您数字世界的中心。它上面可能保存着照片和视频等回忆,以及您不再联系的朋友和家人发来的旧电子邮件。您可能花了数小时导入整个 CD 收藏。您还可能保存着重要文档,例如演示文稿和工作文件、家庭账户或学校或大学的作业。 如果由于某种原因您丢失…...
SpringBoot:解析excel
解析Excel文件,可以使用Apache POI库 <dependency><groupId>org.apache.poi</groupId><artifactId>poi-ooxml</artifactId><version>4.1.2</version> </dependency> 上代码: /*** <b>Functio…...
Tomcat窗口运行修改窗口标题显示项目日期时间
1、修改配置文件catalina.bat文件 在Tomcat路径 bin文件夹下 set TITLETomcat.xxx.Server [%DATE% %TIME%] 显示:Tomcat.xxx,Server [2024/09.18 周三 12:01:30]...

8-----手机机型维修工具助手 功能较全 涵盖解锁 刷机 修复等选项 维修推荐
上图是一款功能较全的维修加密狗。目前可以无限制 任何人使用。看图片可以了解其中涵盖刷机 解锁 修复分区 查看短接图 安装驱动 修复基带等等选项。而且其中有针对各个机型型号的对应功能操作。以及一些rec5.0相关的操作选项。 通过此博文了解 ★★★★★此工具涵盖的一些…...

集群聊天服务器项目【C++】(四)cmake介绍和简单使用
我们上次用shell命令和vscode编译链接muduo库服务端代码,本章节实现编写CMakeLists.txt来编译项目。本次简单介绍CMake,并用Cmake编译上次的muduo服务器代码。 1.为什么使用cmake 我们在编译项目时,如果编写Makefile的话,常常会…...

Nginx+Tomcat(负载均衡、动静分离)
目录 一、Nginx概述 1.Nginx应用 二、正向代理和反向代理 1.正向代理 1.1主要作用 1.2工作原理 2.反向代理 2.1主要作用 2.2工作原理 三、负载均衡模式 1.轮询 2.最少连接数 3.IP 哈希 4.加权轮询 5.最少时间算法 6.一致性哈希 四、规划部署负载均衡和反向…...

前端分段式渲染较长文章
实现思路: 1. 后端返回整篇文章。 2. JavaScript 分段处理:将文章按一定的字符或段落长度分割,然后逐步将这些段落追加到页面上。 3. 定时器或递归调用:使用 setInterval 或 setTimeout 来控制段落的逐步渲染。 代码实现示例 …...

C#程序员的堕落从nuget开始:将自己的代码发布到nuget
初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github:codetoys,所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的,可以在任何平台上使用。 源码指引:github源…...
【C/C++语言系列】malloc、calloc和realloc区别和用法
这三个函数都是在堆区分配内存的函数,头文件都是: #include<stdlib.h>下面分别介绍这三个函数: malloc: 函数原型: void *malloc(unsigned int num_bytes);功能:堆区开辟一段内存空间 num_nytes&…...

【Linux】POSIX信号量与、基于环形队列实现的生产者消费者模型
目录 一、POSIX信号量概述 信号量的基本概念 信号量在临界区的作用 与互斥锁的比较 信号量的原理 信号量的优势 二、信号量的操作 1、初始化信号量:sem_init 2、信号量申请(P操作):sem_wait 3、信号量的释放(…...
Spring Boot-消息队列相关问题
Spring Boot 消息队列相关问题及解决方案 消息队列(Message Queue, MQ)在分布式系统中的应用越来越广泛,尤其是在解耦系统、异步通信、负载均衡等场景中起到了至关重要的作用。消息队列为不同的服务提供了一种异步通信的机制,使得…...

[数据集][目标检测]岩石种类检测数据集VOC+YOLO格式4766张9类别
数据集格式:Pascal VOC格式YOLO格式(不包含分割路径的txt文件,仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数):4766 标注数量(xml文件个数):4766 标注数量(txt文件个数):4766 标注…...

图像分割基本知识
计算机视觉和图像处理 Tensorflow入门深度神经网络图像分类目标检测图像分割 图像分割 一、目标分割1.1 图像分割的定义1.2 任务类型1.2.1 任务描述1.2.2 任务类型 二、语义分割2.1 FCN网络2.1.1网络结构 2.2 Unet网络 三、UNet案例3.1 数据集获取3.1.1 设置相关信息3.1.2 图像…...

LIN总线CAPL函数——干扰LIN帧响应段(linInvertRespBit )
🍅 我是蚂蚁小兵,专注于车载诊断领域,尤其擅长于对CANoe工具的使用🍅 寻找组织 ,答疑解惑,摸鱼聊天,博客源码,点击加入👉【相亲相爱一家人】🍅 玩转CANoe&…...

【HarmonyOS 5.0】DevEco Testing:鸿蒙应用质量保障的终极武器
——全方位测试解决方案与代码实战 一、工具定位与核心能力 DevEco Testing是HarmonyOS官方推出的一体化测试平台,覆盖应用全生命周期测试需求,主要提供五大核心能力: 测试类型检测目标关键指标功能体验基…...
django filter 统计数量 按属性去重
在Django中,如果你想要根据某个属性对查询集进行去重并统计数量,你可以使用values()方法配合annotate()方法来实现。这里有两种常见的方法来完成这个需求: 方法1:使用annotate()和Count 假设你有一个模型Item,并且你想…...

多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)
前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块,…...

搭建DNS域名解析服务器(正向解析资源文件)
正向解析资源文件 1)准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2)服务端安装软件:bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...
LRU 缓存机制详解与实现(Java版) + 力扣解决
📌 LRU 缓存机制详解与实现(Java版) 一、📖 问题背景 在日常开发中,我们经常会使用 缓存(Cache) 来提升性能。但由于内存有限,缓存不可能无限增长,于是需要策略决定&am…...

R 语言科研绘图第 55 期 --- 网络图-聚类
在发表科研论文的过程中,科研绘图是必不可少的,一张好看的图形会是文章很大的加分项。 为了便于使用,本系列文章介绍的所有绘图都已收录到了 sciRplot 项目中,获取方式: R 语言科研绘图模板 --- sciRplothttps://mp.…...
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析
Java求职者面试指南:Spring、Spring Boot、Spring MVC与MyBatis技术解析 一、第一轮基础概念问题 1. Spring框架的核心容器是什么?它的作用是什么? Spring框架的核心容器是IoC(控制反转)容器。它的主要作用是管理对…...

链式法则中 复合函数的推导路径 多变量“信息传递路径”
非常好,我们将之前关于偏导数链式法则中不能“约掉”偏导符号的问题,统一使用 二重复合函数: z f ( u ( x , y ) , v ( x , y ) ) \boxed{z f(u(x,y),\ v(x,y))} zf(u(x,y), v(x,y)) 来全面说明。我们会展示其全微分形式(偏导…...

Linux入门(十五)安装java安装tomcat安装dotnet安装mysql
安装java yum install java-17-openjdk-devel查找安装地址 update-alternatives --config java设置环境变量 vi /etc/profile #在文档后面追加 JAVA_HOME"通过查找安装地址命令显示的路径" #注意一定要加$PATH不然路径就只剩下新加的路径了,系统很多命…...