多态与虚函数、虚函数表、对象的内存模型的思考

news2025/1/24 2:12:50

我在这就不详细说多态、虚函数是什么了,简单理解为:

        1.基类定义虚函数

        2.派生类重定义/重写(override)基类的虚函数

        3.基类指针(引用)指向(绑定)到派生类对象

        4.基类指针(引用)调用虚函数

就可以实现 基类指针(引用)有多种形态

想通过一个代码案例去进行分析,代码来自C++虚函数表剖析 | Leo的技术分享,下面的图片也是参考的这个文章:

#include <iostream>
using namespace std;

class A {
public:
    virtual void vfunc1() { cout << "A::vfunc1" << endl; }
    virtual void vfunc2() { cout << "A::vfunc2" << endl; }
    void func1() { cout << "A::func1" << endl; }
    void func2() { cout << "A::func2" << endl; }
private:
    int m_data1, m_data2;
};

class B : public A {
public:
    virtual void vfunc1() { cout << "B::vfunc1" << endl; }
    void func1() { cout << "B::func1" << endl; }
private:
    int m_data3;
};

class C: public B {
public:
    virtual void vfunc2() { cout << "C::vfunc2" << endl; }
    void func2() { cout << "C::func2" << endl; }
private:
    int m_data1, m_data4;
};

int main() {
    A a;
    B b;
    C c;
    A* pa = &a;
    A* pb = &b;
    A* pc = &c;
    B* pb2 = &c;

    pa->vfunc1();
    pa->vfunc2();

    pb->vfunc1();
    pb->vfunc2();

    pc->vfunc1();
    pc->vfunc2();

    pb2->vfunc1();
    pb2->vfunc2();

    return 0;
}

输出为:

A::vfunc1
A::vfunc2
B::vfunc1
A::vfunc2
B::vfunc1
C::vfunc2
B::vfunc1
C::vfunc2

首先,只要类中有虚函数(不管是继承的、还是重写的、或者是新建的),都会有虚函数表,而虚函数表存在于类的内存布局中,当类实例化对象的时候,会在对象的内存布局前加上一个虚函数表指针,用来指向虚函数表

对于上面中的类A,其虚函数表为:(注意,虚函数表是位于类的,而不是某个具体的对象)

虚函数表 A::vtable
-------------------
0: A::vfunc1
1: A::vfunc2

注意,对于非虚函数,其实就是代码段,是类所有的对象共享的,而数据成员是属于某个特定对象的。

所以对于对象a,其内存布局为:

// 基类 A 的内存模型
|-----------------|
|  A::vtable ptr  |  (指向 A::vtable)
|-----------------|
|   m_data1       |
|   m_data2       |
|-----------------|

其中A::vtable ptr为虚函数表指针,指向虚函数表。

接着看类B,虚函数表为:

虚函数表 B::vtable (继承自 A::vtable)
-------------------
0: B::vfunc1
1: A::vfunc2

其中B::vfunc1是类B重写(override)的虚函数,而A::vfunc2是类B继承自类A的,未进行重写。

对于对象b,其内布局为:

// 派生类 B 的内存模型
|-----------------|
|  B::vtable ptr  |  (指向 B::vtable)
|-----------------|
|   m_data1 (A)   |
|   m_data2 (A)   |
|   m_data3 (B)   |
|-----------------|

接着看类C,虚函数表为:

虚函数表 C::vtable (继承自 B::vtable)
-------------------
0: B::vfunc1
1: C::vfunc2

其中C::vfunc2是类重写(override)的虚函数(离C最近的继承->类B),而B::vfunc1是类C继承自类B的,未进行重写。

这里需要注意,不是要把重写的虚函数放到继承的虚函数前,虚函数表内的虚函数指针布局是根据函数申明顺序来的!

对于对象c,其内布局为:

|-----------------|
|  C::vtable ptr  |  (指向 C::vtable)
|-----------------|
|   m_data1(A)    |
|   m_data2(A)    |
|   m_data3(B)    |
|   m_data1(C)    |
|   m_data4(C)    |
|-----------------|

注意C中有2个m_data1,一个继承来自类A,一个为C自己定义的。

总的来说:“对象的虚表指针用来指向自己所属类的虚表,虚表中的函数指针会指向其继承的最近的一个类的虚函数

参考:

C++虚函数表剖析 | Leo的技术分享

Chapter12:多态——从虚函数表到RTTI(二) - 知乎

虚函数表存储的位置(解析C++内存分配及其编译分段)_c++虚表存在哪里-CSDN博客

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

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

相关文章

大数据Doris(十五):Doris表的字段类型

文章目录 Doris表的字段类型 一、TINYINT数据类型 二、SMALLINT数据类型 三、INT数据类型

以太网【FPGA】

1物理&#xff1a; 2接线&#xff1a; 信号名 信号类型 对应引脚 备注 sys_clk Input B5 系统晶振输入时钟&#xff0c;频率 50MHz sys_rst_n Input E8 系统复位信号&#xff0c;低有效 eth_rxc Input E17 PHY 输入时钟&#xff0c;频率 125MHz eth_rx_ctl Inpu…

傅里叶分析和小波分析

从傅里叶变换到小波变换&#xff0c;并不是一个完全抽象的东西&#xff0c;可以讲得很形象。小波变换有着明确的物理意义&#xff0c;如果我们从它的提出时所面对的问题看起&#xff0c;可以整理出非常清晰的思路。 下面我就按照傅里叶-->短时傅里叶变换-->小波变换的顺…

损失函数(Loss Function)一文详解-聚类问题常见损失函数Python代码实现+计算原理解析

损失函数(Loss Function)一文详解-聚类问题常见损失函数Python代码实现计算原理解析 前言 损失函数无疑是机器学习和深度学习效果验证的核心检验功能&#xff0c;用于评估模型预测值与实际值之间的差异。我们学习机器学习和深度学习或多或少都接触到了损失函数&#xff0c;但…

SuperMap iServer 11i(2023)安全性提升汇总

作者&#xff1a;lisong 目录 账户信息合规度校验规则扩展功能图片验证码登录功能Web服务提供者密码加密数据库密码加密漏洞修复 SuperMap iServer 11i&#xff08;2023&#xff09;产品安全性相关的提升众多&#xff0c;涵盖账户安全、服务安全以及漏洞修复等方面&#xff0c;…

2023杭州·云栖大会:我在云栖看数智中国

目录 模型即服务&#xff08;MaaS&#xff0c;Model as a Service&#xff09;全球首个李白数字展我在云栖看数智中国 云栖之眼、视频云3D渲染、数字人…… 10月31日到11月2日&#xff0c;2023云栖大会在杭州市西湖区云栖小镇火热进行&#xff0c;本次的主题为“ 计算&#xff…

YOLO目标检测——红外多目标检测数据集【含对应voc、coco和yolo三种格式标签】

实际项目应用&#xff1a;自动驾驶、安防监控等数据集说明&#xff1a;红外多目标检测数据集&#xff0c;真实场景的高质量图片数据&#xff0c;数据场景丰富&#xff0c;含有行人、汽车、自行车、摩托、消防栓、指示牌、狗等图片标签说明&#xff1a;使用lableimg标注软件标注…

题解数量上三百了

题解数量上三百了 持之以恒&#xff0c;不断进步。

近独立粒子的最概然分布

近独立粒子&#xff1a;粒子之间相互作用微弱基本粒子中&#xff0c;自旋量子数为半整数的有 电子 、 质子 、中子、中微子自旋量子数为整数的有 光子、pi介子 经典力学描述系统的微观运动状态 经典力学中&#xff0c;全同粒子可以分辨量子力学&#xff0c;全同粒子不可以分辨微…

JMeter接口测试性能测试

目前最新版本发展到5.0版本&#xff0c;需要Java7以上版本环境&#xff0c;下载解压目录后&#xff0c;进入\apache-jmeter-5.0\bin\&#xff0c;双击ApacheJMeter.jar文件启动JMemter。 1、创建测试任务 添加线程组&#xff0c;右击测试计划&#xff0c;在快捷菜单单击添加-…

【腾讯云 HAI域探秘】基于ChatGLM和StableDiffusion的小学一年级语文教学方案创作实践与经验分享

前言 目前腾讯云HAI正在内测中&#xff0c;腾讯云HAI为开发者量身打造的澎湃算力平台。无需复杂配置&#xff0c;便可享受即开即用的GPU云服务体验。在 HAI 中&#xff0c;根据应用智能匹配并推选出最适合的GPU算力资源&#xff0c;以确保您在数据科学、LLM、AI作画等高性能应用…

Java 算法篇-深入了解二分查找法

&#x1f525;博客主页&#xff1a; 小扳_-CSDN博客 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 目录 1.0 二分查找法的说明 2.0 二分查找实现的多种版本 2.1 二分查找的基础版本 2.2 二分查找的改动版本 2.3 二分查找的平衡版本 2.4 二分查找的官方版本 3.0 二分查找的应用 1…

OpenCV的绘图工具(rectangle、circle、line、polylines、putText)常用方法简介【C++的OpenCV 第十五课】

&#x1f389;&#x1f389;&#x1f389; 欢迎各位来到小白 p i a o 的学习空间&#xff01; \color{red}{欢迎各位来到小白piao的学习空间&#xff01;} 欢迎各位来到小白piao的学习空间&#xff01;&#x1f389;&#x1f389;&#x1f389; &#x1f496; C\Python所有的入…

项目管理之如何分配项目工作任务

项目资源配置技术是项目管理中至关重要的环节&#xff0c;它直接影响到项目的效率、质量以及最终的成果。本文将介绍项目资源配置技术&#xff0c;包括小组团队主管配置、保持团队规模小型化、保持团队人员能力均衡、为保证团队速度及质量&#xff0c;团队资源复用数量限制以及…

智能工厂架构

引:https://www.bilibili.com/video/BV1Vs4y167Kx/?spm_id_from=333.788&vd_source=297c866c71fa77b161812ad631ea2c25 智能工厂框架 智能工厂五层系统框架 MES 数据共享 <

Leetcode—2103.环和杆【简单】

2023每日刷题&#xff08;十六&#xff09; Leetcode—2103.环和杆 实现代码 struct ring{int r;int g;int b; }sticks[10]{0};int countPoints(char * rings){char *p rings;int i;for(i 0; i < 10; i) {sticks[i].r 0;sticks[i].g 0;sticks[i].b 0;}while(*p ! \0)…

大厂面试题-为什么Netty线程池默认大小为CPU核数的2倍

目录 1、分析原因 2、如何衡量性能指标 3、总结与使用建议 1、分析原因 我们都知道使用多线程的本质是为了提升程序的性能&#xff0c;总体来说有两个最核心的指标&#xff0c;一个延迟&#xff0c;一个吞吐量。延迟指的是发出请求到收到响应的时间&#xff0c;吞吐量指的是…

【golang】Reflect反射整理、值修改、反射结构体、应用

Reflect 整理 反射是用程序检查其所拥有的结构&#xff0c;尤其是类型的一种能力&#xff1b;这是元编程的一种形式。反射可以在运行时检查类型和变量&#xff0c;例如&#xff1a;它的大小、它的方法以及它能“动态地”调用这些方法。这对于没有源代码的包尤其有用。这是一个强…

C++引用概述

变量名实质上是一段连续存储空间的别名&#xff0c;是一个标号(门牌号)&#xff0c;程序中通过变量来申请并命 名内存空间&#xff0c;通过变量的名字可以使用存储空间。引用是 C中新增加的概念&#xff0c;引用可以看作 一个已定义变量的别名。 引用的语法&#xff1a; Type&…

第二章 探究活动Activity

一、Activity的用法 1. Activity 任何活动都应该重写Activity的onCreate()方法 项目中在res添加任何资源都会在R文件生成一个相应的资源id 所有的活动都要在AndroidManifest.xml中进行注册才能生效 <activityandroid:name".FirstActivity"android:label"T…