【C++】早绑定、析构与多态 | 一道关于多态的选择题记录

今天在和群友聊天的时候看到了一道很坑的题目,分享给大家

1.看题!

先来看看题目

struct Dad
{
public:Dad(){ echo();}~Dad(){ echo();}virtual void echo() {cout << "DAD ";}
};struct Son:Dad
{
public:void echo() const override {cout << "SON ";}
};Son ss;

请问这个的输出是什么?

A  "DAD DAD "
B  "DAD SON "
C  "SON DAD "
D  "SON SON "
E  编译出错
F  运行出错

答案是E,编译出错!

2.涉及到的知识点

2.1 知识点

先来说说这道题目里面涉及到了什么知识点

  • 多态调用;
  • 多态重写函数需要满足什么条件;
  • 类内函数后加const的作用;
  • 类内函数后加override的作用;
  • 什么是早绑定和晚绑定

一个一个复习吧!

  • 多态调用是父类指针/引用指向子类时,调用虚函数会调用子类重写后的版本
  • 多态重写函数的条件:函数名/参数/返回值都必须相同(注意还有协变)
  • 类内函数后加const修饰的是这个对象的this指针,被修饰的函数中无法修改类内成员变量
  • 类内函数后加override是让编译器来严格检查是否构成重载
  • 早绑定:静态绑定;晚绑定:动态绑定(具体请看CPP多态的博客)

2.2 分析题目

注意看父类和子类中这两个echo()函数的区别

virtual void echo(){}//父类
void echo() const override {}//子类

首先需要说明的是,子类函数中virtual关键字是可以省略的,但即便省略了,这个函数依旧是个虚函数。

这里子类的函数中多了const修饰,而这个const修饰的就是函数中隐含的this指针,此时子类中echo()函数的参数就发生了变化!

virtual void echo(Son* this) { } // 不加const
virtual void echo(const Son* this) { } // 加const

正是因为这里的this指针出现了const的修饰,所以子类的echo和父类echo的参数类型不同,不构成虚函数重写!再加上override关键字的严格检查,会直接编译报错!

正确的写法是删除子类echo中的const或者给父类echo函数加上const

3.再来看题

好了,坑人的点看完了,再来看个「常规」的,就是把上面的题干改成能编译通过的。此时又应该选谁呢?

struct Dad
{
public:Dad(){ echo();}~Dad(){ echo();}virtual void echo() const{cout << "DAD ";}
};struct Son:Dad
{
public:void echo() const override {cout << "SON ";}
};Son ss;
A  "DAD DAD "
B  "DAD SON "
C  "SON DAD "
D  "SON SON "

image-20230822211806379

编译运行,可以看到,结果是DAD DAD,应该选A

3.1 分析

在给 Son 类定义构造函数和析构函数时,没有指定调用父类的对应构造函数和析构函数。因此,在创建 Son 对象 ss 时,会默认调用 Dad 类的构造函数和析构函数。

由于 Dad 类中的构造函数和析构函数调用了虚函数 echo(),而这个虚函数在子类 Son 中被重写,所以会根据对象类型调用相应的重写函数。然而,在构造函数和析构函数中,虚函数机制不会按照预期工作。

构造函数中调用虚函数时,会忽略动态绑定机制,直接调用父类的函数版本。因此,在 Dad 的构造函数中调用 echo(),实际上调用的是 Dad 类中的 echo() 函数,而不是 Son 类中的重写版本。

同样地,析构函数中也会忽略动态绑定机制,直接调用父类的函数版本。所以,在 Dad 的析构函数中调用 echo(),依然调用的是 Dad 类中的 echo() 函数。

因此,当创建 Son 对象 ss 并打印输出时,会先调用 Dad 类的构造函数并打印 "DAD ",然后调用 Dad 类的析构函数并再次打印 "DAD "

3.2 结论

在父类的构造和析构中,对象的版本都被确定为父类的版本,会采用早绑定来调用父类自己的函数,而不是子类的重写后的函数;

简单记忆:父类的构造和析构中如果出现虚函数,只会调用父类自己的函数!


这是因为编译器需要保证正确的构造和析构顺序,如果父类析构里调用子类的虚函数,可能会出现下面的场景

struct Dad
{
public:Dad(){ echo();}~Dad(){ echo();}virtual void echo() const{cout << "DAD ";}
};struct Son:Dad
{
public:Son() {_a = new int(3);}~Son() {delete _a;}void echo() const override {cout << "SON ";delete _a;}
private:int _a;
};Son ss;

如果父类中的析构echo()调用子类重写的函数,此时就会出现子类已经被销毁(子类的析构函数早于父类析构调用)的_a被二次delete,两次delete同一片空间是会报错的!

所以为了避免这种情况,父类的析构中采用早绑定,子类重写的虚函数不会生效!

这种行为是为了确保在对象的构造和析构过程中,按照正确的顺序调用各个类的构造和析构函数,避免在对象处于未完全初始化或已部分销毁状态时调用子类的函数。

包括父类的构造也可以这么理解,如果父类构造里面可以调用子类的虚函数,可能会出现两次对一个子类对象进行new空间,会产生内存泄露;

但构造函数还和虚函数表的初始化有关系,此时虚函数表还没有完全初始化,子类对象尚未构造完成,没有多态调用的条件,所以也不能调用到子类重写后的虚函数。

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

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

相关文章

Java后端开发面试题——微服务篇总结

Spring Cloud 5大组件有哪些&#xff1f; 随着SpringCloudAlibba在国内兴起 , 我们项目中使用了一些阿里巴巴的组件 注册中心/配置中心 Nacos 负载均衡 Ribbon 服务调用 Feign 服务保护 sentinel 服务网关 Gateway Ribbon负载均衡策略有哪些 ? RoundRobinRule&…

vue 项目在编译时,总是出现系统崩的状态,报错信息中有v7 或者 v8 的样式-项目太大内存溢出

vue 项目在编译时&#xff0c;总是出现系统崩的状态&#xff0c;node 命令框也会报错&#xff0c;如下图&#xff1a;有v7 或者 v8 的样式。 原因分析&#xff1a; 分析&#xff1a;遇到与上面图片相似的问题&#xff0c;我们要首先要想到是否是 有关内存的问题&#xff0c;当然…

传输层协议——TCP(下)

文章目录 1. listen的第二个参数2. 滑动窗口3. 流量控制4. 拥塞控制5. 延迟应答6. 捎带应答7. 面向字节流7.1 粘包问题 8. TCP异常情况10. TCP小结 1. listen的第二个参数 listen的第二个参数&#xff0c;叫做底层的全连接队列的长度&#xff0c;算法是&#xff1a;n1&#xf…

Elasticsearch(十四)搜索---搜索匹配功能⑤--全文搜索

一、前言 不同于之前的term。terms等结构化查询&#xff0c;全文搜索首先对查询词进行分析&#xff0c;然后根据查询词的分词结果构建查询。这里所说的全文指的是文本类型数据&#xff08;text类型&#xff09;,默认的数据形式是人类的自然语言&#xff0c;如对话内容、图书名…

(6)(6.2) 任务命令

文章目录 前言 6.2.1 概述 6.2.2 导航命令 6.2.3 条件命令 6.2.4 DO命令 前言 本文介绍了 Copter、Plane 和 Rover 切换到自动模式时支持的任务指令。 &#xff01;Warning 这是一项正在进行中的工作&#xff0c;尚未经过全面审核。有关 Copter 的更佳列表&#xff0c;请…

MySQL视图

一、视图-介绍及基本语法 视图&#xff08;View&#xff09;是一种虚拟存在的表。视图中的数据并不在数据库中实际存在&#xff0c;行和列数据来自定义视图的查询中使用的表&#xff0c;并且是在使用视图时动态生成的。 通俗的讲&#xff0c;视图只保存了查询的SQL逻辑&#xf…

Chrome如何安装插件(文件夹)

1.下载的插件 说明&#xff1a;插件文件夹 2.打开扩展程序位置 3.点击已加载的扩展程序 说明&#xff1a;找到插件的位置 4.报错 说明&#xff1a;那还要进入文件里面。 5.插件的位置 说明&#xff1a;如果已经安装了插件&#xff0c;那么需要查看插件的位置。chrome输入 …

【OpenCV学习笔记】我的OpenCV学习之路

刚开始接触OpenCV是因为需要进行图像的处理&#xff0c;由于之前没有接触过&#xff0c;所以只能自己进行学习&#xff0c;下面将学习的过程做简单记录分享。 OpenCV专栏链接 OpenCV学习笔记 一、引言 OpenCV&#xff08;Open Source Computer Vision Library&#xff09;是…

基于Python的图像信息隐藏技术的设计与实现

博主介绍&#xff1a;✌csdn特邀作者、博客专家、java领域优质创作者、博客之星&#xff0c;擅长Java、微信小程序、Python、Android等技术&#xff0c;专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推…

Docker创建 LNMP 服务+Wordpress 网站平台

文章目录 Docker创建 LNMP 服务Wordpress 网站平台一.环境及准备工作1.项目环境2.服务器环境3.任务需求 二.Linux 系统基础镜像三.docker构建Nginx1.建立工作目录上传安装包2.编写 Dockerfile 脚本3.准备 nginx.conf 配置文件4.生成镜像5.创建自定义网络6.启动镜像容器7.验证 n…

【TA 挖坑03】雾效 | 透光材质 | Impostor | 厚度转球谐

仍旧是记录下半年想要做的东西&#xff0c;很有趣&#xff0c;实现“一团雾效” “面片也有立体感” 等等效果的一些技术上的方法。 仅粗浅记录&#xff0c;保证之后自己填坑的时候看得懂就行&#xff01; 透光 -> 透光材质ShadingModel 《永劫无间》透光材质的渲染&…

机器人制作开源方案 | 滑板助力器

我们可以用一块废滑板做些什么呢&#xff1f; 如今&#xff0c;越来越多的人选择电动滑板作为代步工具或娱乐方式&#xff0c;市场上也涌现出越来越多的电动滑板产品。 &#xff08;图片来源&#xff1a;Backfire Zealot X Belt Drive Electric Skateboard– Backfire Board…

Java注解语法

Java注解语法 1. 前置基础 ​ 学习java反射语法 JAVA通过反射使用公共构造方法和私有构造方法来创建对象 2. Java注解是什么&#xff1f; ​ Java注解是代码中的特殊标记&#xff0c;比如Override、Test等&#xff0c;作用是&#xff1a;让其他程序根据注解 信息决定怎么执…

【xxl-job快速入门搭建】

目录标题 xxl-job快速入门搭建源码地址项目结构初始化数据库启动项目1、启动服务端2、启动任务执行器端 MD文档指导教程功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内…

SAP‘s ECC6 EoL(End of Life) 支持服务声明 2027?

前言 一、EoL公告信息&#xff0c;2027&#xff1f; 二、继续使用ECC6.0的选项 1.引入第三方支持 2.S/4 HANA 3.SAP Business ByDesign 4.SAP Business One 总结 最新的公告是&#xff1a;2027年&#xff0c;SAP ECC 6.0将停止得到支持&#xff0c;并退出主流SAP支持&am…

c++ day1

定义一个命名空间Myspace&#xff0c;包含以下函数&#xff1a;将一个字符串中的所有单词进行反转&#xff0c;并输出反转后的结果。例如&#xff0c;输入字符串为"Hello World"&#xff0c;输出结果为"olleH dlroW"&#xff0c;并在主函数内测试该函数。 …

动态不确定性的动态S过程(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

同步、异步无障碍:Python异步装饰器指南

一、引言 Python异步开发已经非常流行了&#xff0c;一些主流的组件像MySQL、Redis、RabbitMQ等都提供了异步的客户端&#xff0c;再处理耗时的时候不会堵塞住主线程&#xff0c;不但可以提高并发能力&#xff0c;也能减少多线程带来的cpu上下文切换以及内存资源消耗。但在业务…

回归预测 | MATLAB实现SSA-RF麻雀搜索优化算法优化随机森林算法多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现SSA-RF麻雀搜索优化算法优化随机森林算法多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09; 目录 回归预测 | MATLAB实现SSA-RF麻雀搜索优化算法优化随机森林算法多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09;…

2023年国赛 高教社杯数学建模思路 - 案例:退火算法

文章目录 1 退火算法原理1.1 物理背景1.2 背后的数学模型 2 退火算法实现2.1 算法流程2.2算法实现 建模资料 ## 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 退火算法原理 1.1 物理背景 在热力学上&a…