探索:C++继承中虚表与虚基表的内存存储

探讨:菱形虚拟继承的虚基表和虚表

在继承和多态里,总是能听到虚表、虚基表这样的词汇,没有洞悉其根本的人很容易将它们混淆,因此,我们对这两个“虚”“表”进行实践,来更好地理解它们。

通俗些说:
虚基表,即虚基类表,存放的是偏移量,是该表的位置与基类那一部分内容的地址之间的距离。
虚表:即虚函数表,存放的是函数指针,是某个类中所有虚函数的指针的集合。

  1. 初始&菱形虚拟继承

    有这么一段菱形虚拟继承的代码:

    class A 
    { 
    public: 
    	void func1() {
    		cout << "A::func1()" << endl;
    	} 
    	int a;
    }; 
    class B : virtual public A 
    { 
    public: 
    	int b;
    };
    class C : virtual public A
    {
    public:
    	int c;
    };
    class D : public B, public C
    {
    public:
    	int d;
    };
    
    int main()
    {
    	D d1;
    	d1.a = 1;
    	d1.b = 2;
    	d1.c = 3;
    	d1.d = 4;
    	return 0;
    }
    

    这是一个典型的菱形虚拟继承,我们通过调试,来看看它在内存中的布局:

    在这里插入图片描述

    因为没有虚函数,所以没有虚函数表(虚表)。
    而虚基类表(虚基表)来自于:菱形虚拟继承(虚拟:解决菱形继承的二义性和冗余)

  2. 重写/覆盖

    class A 
    { 
    public: 
    	virtual void func1() 
    	{
    		cout << "A::func1()" << endl;
    	} 
    	int a;
    }; 
    class B : virtual public A 
    { 
    public: 
    	void func1() 
    	{
    		cout << "B::func1()" << endl;
    	} 
    	int b;
    };
    class C : virtual public A
    {
    public:
    	int c;
    };
    class D : public B, public C
    {
    public:
    	int d;
    };
    
    int main()
    {
    	D d1;
    	d1.a = 1;
    	d1.b = 2;
    	d1.c = 3;
    	d1.d = 4;
    	return 0;
    }
    

    此时B中的func1()与A中的func1()构成重写(覆盖),整个过程请参看下面的调试过程:

    在这里插入图片描述

    刚才仅仅是在B中重写,那如果C中也进行重写呢?此时到底是重写B的实现,还是C的实现呢?
    答案是:都不是!
    如果B和C同时对A的func1()进行重写,编译器会报错,因为不明确!此时只需要在D中,也进行func1()的重写,那么就OK了!编译器会把D的实现重写进去,不会写B和C的实现。(当然B和C的重写并非没用,当有些场景创建“B b1;”B类型的对象b1时,就可以用到B的重写了)

  3. 中间两个派生类有自己的虚函数

    刚才的代码都是基类A的虚函数,如果派生类自己也有虚函数呢?请看:

    class A 
    { 
    public: 
    	virtual void func1() 
    	{
    		cout << "A::func1()" << endl;
    	} 
    	int a;
    }; 
    class B : virtual public A 
    { 
    public: 
    	void func1() 
    	{
    		cout << "B::func1()" << endl;
    	} 
        virtual void funcB()
        {
            cout << "B::funcB()" << endl;
        }
    	int b;
    };
    class C : virtual public A
    {
    public:
        void func1() 
    	{
    		cout << "C::func1()" << endl;
    	} 
        virtual void funcC()
        {
            cout << "C::funcC()" << endl;
        }
    	int c;
    };
    class D : public B, public C
    {
    public:
        void func1() 
    	{
    		cout << "D::func1()" << endl;
    	} 
    	int d;
    };
    
    int main()
    {
    	D d1;
    	d1.a = 1;
    	d1.b = 2;
    	d1.c = 3;
    	d1.d = 4;
    	return 0;
    }
    

    两个中间的派生类B和C,分别加上自己的虚函数funcB()funcC(),此时就没有刚才那么简单了,请看下图:

    在这里插入图片描述

    在原先的基础上,B和C分别多了一个虚函数表,存放它们自己的虚函数的地址。

  4. 最后一个派生类有自己的虚函数

    刚才是中间两个派生类有自己的虚函数,它们会产生自己的虚函数表,那么如果最后一个派生类(多继承的那个)也有自己的虚函数呢?你肯定以为它也会产生一个自己的虚函数表,但是你错了。请看下面的调试图:

    在这里插入图片描述

    至此可以窥得,C++多继承中的菱形继承,是多么的让人费解!也正因如此,我们不必要时,尽量避免写出菱形虚拟继承这样的结构出来,这对大家都好!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AI新工具(20240313) 世界上第一个完全自主的AI软件工程师Devin 已经开始接外包了;又一个开源本地知识库问答系统

1: Cognition AI Devin 世界上第一个完全自主的AI软件工程师Devin 已经开始接外包了 Devin是世界上第一个完全自主的AI软件工程师&#xff0c;具备长期推理和规划的能力&#xff0c;能够执行复杂的工程任务&#xff0c;包括学习、修复错误、与用户实时合作等。Devin可以学习并…

Vue Slot插槽:组件化的艺术

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

前端面试题汇总

基础面试题 1.new 操作符做了那些事 function Fun(name){this.name name } Fun.prototype.sayHi funtion(){console.log(this.name) }function mockCreate(fn, ...args){let obj Object.create({}) // 创建一个空对象Object.setPrototypeOf(obj, fn.prototype) // 空对象…

基于LIO-SAM 算法的三维激光SLAM 建图

运行环境 Linux&#xff1a;Ubuntu18.04ros&#xff1a;MelodicCeres Solver 2.0.0&#xff08;Ubuntu18.04安装Ceres&#xff09;PCL 1.8.1&#xff08;Ubuntu系统的PCL、Eigen卸载和安装&#xff09;gtsam-4.0.0-alpha2 或者 4.0.2 1 背景介绍 在自动驾驶的感知方案中&…

c语言之汉诺塔的实现

思路 汉诺塔问题就是有三个盘子&#xff0c;让我们把其中一个盘子上的东西全移到另一个盘子上&#xff0c;注意的是中途必须满足大东西必须在小东西下面。 这里&#xff0c;我们有A B C三个盘子&#xff0c;假如A上有一个珠子&#xff0c;那我们直接把这一个移到C上就可以&am…

Python和Tensorboard的下载和安装

Python和Tensorboard的下载和安装 Python的下载和安装Python下载Python安装测试Python Tensorboard的下载和安装Tensorboard 简介Tensorboard下载Tensorboard使用urllib3报错 Python的下载和安装 Python下载 Python官方下载链接&#xff1a;https://www.python.org/downloads…

2024年3月11日 算法刷题记录

2024年3月11日 习题 2.4 Repeater&#xff08;北京大学复试上机题&#xff09; 链接 题目大意 给你一个仅包含一种字符和空格的模板&#xff0c;模板显示如何创建无尽的图片&#xff0c;将字符用作基本元素并将它们放在正确的位置以形成更大的模板&#xff0c;然后不断进行…

Windows C++ 使用WinAPI实现RPC

demo下载地址&#xff1a;https://download.csdn.net/download/2403_83063732/88958730 1、创建IDL文件以及acf文件&#xff08;创建helloworld.idl helloworld.acf&#xff09; 其中IDL文件&#xff1a; import "oaidl.idl"; import "ocidl.idl"; [ …

AI日报:一个新的“科技超级周期”正在出现

文章目录 技术周期预测可连接设备 技术周期 未来学家艾米韦伯表示&#xff0c;人工智能和其他两种通用技术将迎来一个新的“技术超级周期”&#xff0c;预计将在经济中创造“实质性和持续性”的变化。 她在SXSW 2024上表示&#xff0c;过去的科技超级周期是由通用技术引发的&…

鸿蒙开发之快速入门

一:下载开发工具 鸿蒙的开发工具叫DevEco 下载点击 其他部分都一直next 就行,这个页面出现的install 建议都点击install 然后单独选择安装目录 可能存在的问题 就是之前安装nodejs&#xff08;比如自己开发web或者RN等情况&#xff09;版本低 等情况 所以建议你单独安装一次 …

【数学】【C++算法】780. 到达终点

作者推荐 视频算法专题 本文涉及知识点 数学 LeetCode780. 到达终点 给定四个整数 sx , sy &#xff0c;tx 和 ty&#xff0c;如果通过一系列的转换可以从起点 (sx, sy) 到达终点 (tx, ty)&#xff0c;则返回 true&#xff0c;否则返回 false。 从点 (x, y) 可以转换到 (x…

Go语言中的锁与管道的运用

目录 1.前言 2.锁解决方案 3.管道解决方案 4.总结 1.前言 在写H5小游戏的时候&#xff0c;由于需要对多个WebSocket连接进行增、删、查的管理和对已经建立连接的WebSocket通过服务端进行游戏数据交换的需求。于是定义了一个全局的map集合进行连接的管理&#xff0c;让所有…

Netty架构详解

文章目录 概述整体结构Netty的核心组件逻辑架构BootStrap & ServerBootStrapChannelPipelineFuture、回调和 ChannelHandler选择器、事件和 EventLoopChannelHandler的各种ChannelInitializer类图 Protocol Support 协议支持层Transport Service 传输服务层Core 核心层模块…

操作系统内功篇:硬件结构之CPU是如何运行的?

本文分5个小结&#xff0c;分别是图灵机工作方式&#xff0c;冯诺依曼结构&#xff0c;总线线路位宽和CPU位宽&#xff0c;程序执行的基本过程&#xff0c; a12的具体执行过程。 一 图灵机的工作方式 图灵机由纸带&#xff0c;读写头组成。读写头上有一些部件例:存储单元&#…

嵌入式驱动学习第三周——linux内核链表

前言 在 Linux 内核中使用最多的数据结构就是链表了&#xff0c;其中就包含了许多高级思想。 比如面向对象、类似C模板的实现、堆和栈的实现。 嵌入式驱动学习专栏将详细记录博主学习驱动的详细过程&#xff0c;未来预计四个月将高强度更新本专栏&#xff0c;喜欢的可以关注本博…

智能指针的讲解

1.为什么要智能指针 首先我们分析一段代码&#xff1a; 1、如果p1这里new 抛异常会如何&#xff1f; 2、如果p2这里new 抛异常会如何&#xff1f; 3、如果div调用这里又会抛异常会如何&#xff1f; int div() {int a, b;cin >> a >> b;if (b 0)throw invalid_ar…

CVE-2024-2074 SpringBoot迷你天猫商城Mini-Tmall sql注入漏洞分析

漏洞简介 Mini-Tmall是一个基于Spring Boot的迷你天猫商城。Mini-Tmall在20231017版本及之前存在一个严重的漏洞&#xff0c;攻击者可以利用该漏洞通过远程执行特定操作来注入恶意SQL语句&#xff0c;从而获取敏感信息或控制数据库。此漏洞影响文件?rtmall/admin/user/1/1的一…

下载API文档

在线看&#xff1a;Overview (Java SE 17 & JDK 17) 离线下载&#xff1a;Java Development Kit 17 Documentation

Python 单元测试

本篇为Python的单元测试的方法及示例 目录 概念 结果 示例 对函数进行测试 创建函数文件 创建测试文件 测试结果 对类进行测试 创建待测试类 创建测试文件 文档测试 创建函数 进行测试 总结 概念 用来对一个函数、一个类或者一个模块来进行正确性校验工作 结果 …

为什么选择线上展览馆,搭建线上展览馆要注意什么

引言&#xff1a; 线上展览馆是一种利用互联网技术&#xff0c;将实体展览馆的展示内容以数字化形式呈现出来的在线观展方式。它打破了时间和空间的限制&#xff0c;使得更多的人可以随时随地参观展览&#xff0c;领略文化的魅力。 一、线上展览馆的优势 1.成本效益高&#x…