当前位置: 首页 > article >正文

C++虚函数与类对象模型深度解析

目录

1. 引言

2. 单继承下的虚函数表

2.1 基本概念

2.2 示例分析

3. 多重继承下的虚函数表

3.1 基本概念

3.2 示例分析

4. 虚函数表指针(vptr)的存储

4.1 单继承

4.2 多重继承

5. 常见面试题解析

问题1:D 继承 B1 和 B2,D 新增虚函数放在哪里?

问题2:D 有几个虚表指针?

问题3:如果 B1 没有虚函数,B2 有虚函数

6. 总结


1. 引言

在C++中,虚函数是实现运行时多态(动态绑定)的核心机制,而虚函数表(vtable)和虚表指针(vptr)是实现这一机制的关键。理解虚函数在类对象模型中的存储方式,对于深入掌握C++面向对象编程至关重要。本文将详细分析:

  • 单继承下的虚函数表布局
  • 多重继承下的虚函数表布局
  • 虚函数表指针(vptr)的存储方式
  • 新增虚函数对虚表的影响

2. 单继承下的虚函数表

2.1 基本概念

当一个类包含虚函数时,编译器会为该类生成一个虚函数表(vtable),存储所有虚函数的地址。每个对象的内存布局中,前4字节(32位系统)或前8字节(64位系统)存储指向虚函数表的指针(vptr)。

2.2 示例分析

class A {
public:virtual void func1() { cout << "A::func1" << endl; }virtual void func2() { cout << "A::func2" << endl; }
};class B : public A {
public:virtual void func1() override { cout << "B::func1" << endl; } // 重写virtual void func3() { cout << "B::func3" << endl; }          // 新增
};

内存布局:

对象虚表指针(vptr)虚表内容
Avptr_AA::func1A::func2
Bvptr_BB::func1(重写), A::func2B::func3(新增)

关键点:

  • B 继承 A,因此 B 的虚表包含 A 的所有虚函数(func1 被重写,func2 保留)。
  • B 新增的 func3 附加到虚表末尾。

3. 多重继承下的虚函数表

3.1 基本概念

在多重继承中,派生类会为每个包含虚函数的基类维护一个独立的虚函数表。如果派生类新增虚函数,它们会附加到第一个基类的虚表末尾

3.2 示例分析

class B1 {
public:virtual void f1() { cout << "B1::f1" << endl; }
};class B2 {
public:virtual void f2() { cout << "B2::f2" << endl; }
};class D : public B1, public B2 {
public:virtual void f1() override { cout << "D::f1" << endl; }  // 重写 B1::f1virtual void f2() override { cout << "D::f2" << endl; }  // 重写 B2::f2virtual void f3() { cout << "D::f3" << endl; }           // 新增虚函数
};

内存布局:

对象虚表指针(vptr)虚表内容
Dvptr_B1D::f1D::f3(新增)
vptr_B2D::f2

关键点:

  • D 继承 B1 和 B2,因此有 2 个虚表指针vptr_B1 和 vptr_B2)。
  • D 新增的 f3 附加到 B1 的虚表末尾(因为 B1 是第一个基类)。
  • B2 的虚表仅存储 D 重写的 f2

4. 虚函数表指针(vptr)的存储

4.1 单继承

  • 只有一个 vptr,位于对象起始地址。
  • 示例:
A a;
B b;
cout << *(void**)&a; // 输出 A 的虚表地址
cout << *(void**)&b; // 输出 B 的虚表地址

4.2 多重继承

  • 每个基类对应一个 vptr,按继承顺序排列。
  • 示例:
D d;
void** vptr1 = *(void***)&d;                     // B1 的 vptr
void** vptr2 = *(void***)((char*)&d + sizeof(B1)); // B2 的 vptr

5. 常见面试题解析

问题1:D 继承 B1 和 B2D 新增虚函数放在哪里?

答案:放在第一个基类 B1 的虚表末尾。

问题2:D 有几个虚表指针?

答案:2 个(对应 B1B2)。

问题3:如果 B1 没有虚函数,B2 有虚函数

6. 总结

继承方式虚表指针数量新增虚函数存储位置
单继承1附加到基类虚表末尾
多重继承等于基类数量附加到第一个基类虚表末尾

关键结论:

  1. 虚函数表(vtable)是实现动态绑定的核心。
  2. 单继承时,派生类虚表包含基类虚函数 + 新增虚函数。
  3. 多重继承时,派生类为每个基类维护独立虚表,新增虚函数放在第一个基类虚表末尾。

相关文章:

C++虚函数与类对象模型深度解析

目录 1. 引言 2. 单继承下的虚函数表 2.1 基本概念 2.2 示例分析 3. 多重继承下的虚函数表 3.1 基本概念 3.2 示例分析 4. 虚函数表指针&#xff08;vptr&#xff09;的存储 4.1 单继承 4.2 多重继承 5. 常见面试题解析 问题1&#xff1a;D 继承 B1 和 B2&#xff0…...

3d世界坐标系转屏幕坐标系

世界坐标 ——> NDC标准设备坐标 ——> 屏幕坐标 标准设备NDC坐标系 屏幕坐标系 .project方法将 将向量(坐标)从世界空间投影到相机的标准化设备坐标 (NDC) 空间。 手动实现HTML元素定位到模型位置&#xff0c;实现模型标签效果&#xff08;和css2Render原理同理&#…...

【2025】基于Springboot + vue + 协同过滤算法实现的旅游推荐系统

项目描述 本系统包含管理员和用户两个角色。 管理员角色&#xff1a; 用户管理&#xff1a;管理系统中所有用户的信息&#xff0c;包括添加、删除和修改用户。 配置管理&#xff1a;管理系统配置参数&#xff0c;如上传图片的路径等。 权限管理&#xff1a;分配和管理不同角…...

AI数据治理破局的战略重构

AI数据治理破局的战略重构 AI正在颠覆传统数据治理模式动态策略驱动的AI治理新模式构建AI时代的数据防护栏结语 人工智能正重塑商业世界&#xff0c;那些真正理解当代数据治理变革的企业将占据决定性优势。 旧日的数据治理手册已经无法应对AI时代的全新挑战&#xff0c;我们需要…...

QT6安装与概念介绍

文章目录 前言installModulesQt Core元对象系统属性系统对象模型对象树和所有者信号 & 槽 前言 QT不是纯粹的C标准&#xff0c;它在此基础上引入MOC编译器&#xff0c;在调用C编译器之前会使用该编译器将非C的内容如 Q_OBJECT、signal:等进行处理。此外QT还引入了对象间通…...

Python包管理工具uv 国内源配置

macOS 下 .config/uv/uv.toml内 pip源 [[index]] url "https://mirrors.tuna.tsinghua.edu.cn/pypi/web/simple/" default true#uv python install 下载源配置无效&#xff0c;需要在项目里配置 # python-install-mirror "https://mirror.nju.edu.cn/githu…...

ABP VNext + Webhook:订阅与异步回调

&#x1f680; ABP VNext Webhook&#xff1a;订阅与异步回调 &#x1f4da; 目录 &#x1f680; ABP VNext Webhook&#xff1a;订阅与异步回调&#x1f3af; 一、背景切入&#xff1a;如何优雅地支持第三方回调&#xff1f;&#x1f3d7; 二、系统架构设计&#x1f50d; 三…...

Docker(二):开机自启动与基础配置、镜像加速器优化与疑难排查指南

引言 docker 的快速部署与高效运行依赖于两大核心环节&#xff1a;基础环境搭建与镜像生态优化。本期博文从零开始&#xff0c;系统讲解 docker 服务的管理配置与镜像加速实践。第一部分聚焦 docker 服务的安装、权限控制与自启动设置&#xff0c;确保环境稳定可用&#xff1b…...

Lua基础语法

文章目录 一、注释二、 数据类型1. 注意事项2. 全局/局部变量 三、 标识符1. 保留字2. 变量3. 动态类型 四、 运算符1. 算术运算符2. 关系运算符3. 逻辑运算符4. 其他运算符 五、 函数1. 固定参函数2. 可变参函数3. 可返回多个值4. 函数作为参数 六、循环控制语句1. while...do…...

2025年渗透测试面试题总结-匿名[实习]安全工程师(安全厂商)(题目+回答)

网络安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 一面技术问题 1. Burp插件原理 2. JavaWeb项目经验 3. CC1-7链原理&#xff08;以CC6为例&#xff0…...

【node.js】实战项目

个人主页&#xff1a;Guiat 归属专栏&#xff1a;node.js 文章目录 1. 项目概览与架构设计1.1 实战项目&#xff1a;企业级电商管理系统1.2 技术栈选择 2. 项目初始化与基础架构2.1 项目结构设计2.2 基础配置管理 3. 用户服务实现3.1 用户服务架构3.2 用户模型设计3.3 用户服务…...

从AD9361 到 ADSY1100 ,中间的迭代产品历史

从 AD9361 到 ADSY1100 的演进&#xff0c;是 Analog Devices&#xff08;ADI&#xff09;在射频收发器&#xff08;RF Transceiver&#xff09;集成化、高性能、宽带宽、低功耗和波束赋形能力方面持续推进的一个路线。以下是其中的重要芯片节点和核心参数对比&#xff1a; 1. …...

免费插件集-illustrator插件-Ai插件-查找选中颜色与pantone中匹配颜色

文章目录 1.介绍2.安装3.通过窗口>扩展>知了插件4.功能解释5.总结 1.介绍 本文介绍一款免费插件&#xff0c;加强illustrator使用人员工作效率&#xff0c;实现查找选中颜色与pantone中匹配颜色。首先从下载网址下载这款插件https://download.csdn.net/download/m0_6731…...

redis集合类型

练习命令使用&#xff0c;具体如下&#xff1a; 练习无序集合类型命令 sadd smembers scard srem sinter sunion sdiff sismember srandmember spop 练习有序集合类型命令 无序集合中的每个元素都是不同的&#xff0c;且没有顺序 创建/追加/删除/查看 127.0.0.1:6379>…...

[爬虫实战] 爬微博图片:xpath的具体运用

博客配套代码发布于github&#xff1a;微博图片 相关知识点&#xff1a;图片懒加载 [爬虫知识] 数据解析 相关爬虫专栏&#xff1a;JS逆向爬虫实战 爬虫知识点合集 爬虫实战案例 这里我们以网页微博图片为例&#xff0c;尝试获取该页面下所有图片并保存。 一、分析网站 刷…...

MySQL中简单的操作

一.数据库 1.1数据库的建立&#xff1a; create database 库名&#xff1b; 1.2数据库的查看&#xff1a; show databases&#xff1b; 1.3数据库的删除&#xff1a; drop database 库名&#xff1b; 二.数据库中的表 2.1表的建立&#xff1a; create table 表名&…...

NNG和DDS

NNG (Nanomsg Next Generation) 和 DDS (Data Distribution Service) 是两种不同的通信协议&#xff0c;各自在不同场景下具有其优势。下面我将对这两种技术进行详细解释&#xff0c;并通过具体的例子来说明它们如何应用在实际场景中。 1. NNG (Nanomsg Next Generation) NNG简…...

防震基座在半导体晶圆制造设备抛光机详细应用案例-江苏泊苏系统集成有限公司

在半导体制造领域&#xff0c;晶圆抛光作为关键工序&#xff0c;对设备稳定性要求近乎苛刻。哪怕极其细微的振动&#xff0c;都可能对晶圆表面质量产生严重影响&#xff0c;进而左右芯片制造的成败。以下为您呈现一个防震基座在半导体晶圆制造设备抛光机上的经典应用案例。 企…...

框架开发与原生开发的权衡:React案例分析(原生JavaScript)

文章目录 框架开发与原生开发的权衡&#xff1a;React案例分析引言框架开发的优势开发效率提升状态管理的便捷性组件复用与生态系统团队协作与规范统一 原生开发的优势性能优化空间学习曲线平缓精细控制与定制化避免版本依赖与迁移成本 实际应用案例分析大型企业应用性能关键型…...

Lua5.4.2常用API整理记录

一、基础函数 1.type(value)​​ 返回值的类型&#xff08;如 "nil", "number", "string", "table", "function" 等&#xff09;。 代码测试&#xff1a; a 0 print(type(a)) a nil print(type(a)) a "aaaaaaaa&…...

Python打卡训练营学习记录Day36

仔细回顾一下神经网络到目前的内容&#xff0c;没跟上进度的同学补一下进度。 作业&#xff1a;对之前的信贷项目&#xff0c;利用神经网络训练下&#xff0c;尝试用到目前的知识点让代码更加规范和美观。 import pandas as pd #用于数据处理和分析&#xff0c;可处理表格数…...

### Mac电脑推送文件至Gitee仓库步骤详解

**核心流程及命令说明&#xff1a;** #### 1. **配置全局Git用户信息** bash git config --global user.name "shenguanling" git config --global user.email "3259125968qq.com" - **作用**&#xff1a;设置提交代码时的作者信息&#xff0…...

官方SDK停更后的选择:开源维护的Bugly Unity SDK

腾讯Bugly&#xff0c;为移动开发者提供专业的异常上报和运营统计&#xff0c;帮助开发者快速发现并解决异常&#xff0c;同时掌握产品运营动态&#xff0c;及时跟进用户反馈。 但是&#xff0c;免费版的Unity SDK已经很久不更新了&#xff0c;会有一些问题和特性缺失&#xff…...

什么是智能体agent?

文章目录 什么是智能体agent&#xff1f;最基本的核心思想我们是如何走到今天以及为什么是现在如何从思维上剖析“一个智能体系统”痛苦的教训结论 什么是智能体agent&#xff1f; 原文链接&#xff1a;https://windsurf.com/blog/what-is-an-agent 本文探讨了AI智能体的核心概…...

【多线程】Java 实现方式及其优缺点

以下是 Java 多线程实现方式及其优缺点的详细说明&#xff1a; 一、Java 多线程核心实现方式 1. 继承 Thread 类 public class MyThread extends Thread {Overridepublic void run() {System.out.println("Thread running: " Thread.currentThread().getName());}…...

Obsidian 数据可视化深度实践:用 DataviewJS 与 Charts 插件构建智能日报系统

Obsidian 数据可视化深度实践&#xff1a;用 DataviewJS 与 Charts 插件构建智能日报系统 一、核心架构解析 本系统基于 Obsidian 的 DataviewJS 和 Charts 插件&#xff0c;实现日报数据的自动采集、可视化分析及智能回溯功能&#xff08;系统架构原理见&#xff09;。其技术…...

Three.js 海量模型加载性能优化指南

一、性能瓶颈分析 1.1 常见性能杀手 问题类型典型表现影响范围Draw Call 爆炸每帧渲染调用超过1000次GPU 渲染性能内存占用过高浏览器进程内存突破1GB加载速度/崩溃风险模型文件过大单个GLB文件超过50MB网络传输时间几何数据冗余重复模型独立加载CPU/GPU资源浪费 1.2 性能监…...

6.4.3_有向无环图描述表达式

有向无环图&#xff1a; 有向图中不存在环即为有向无环图DAG图&#xff0c;即如下V0->V4->v3->V0或者V4->V1->v4就存在环不是有向无环图&#xff0c;即在一个路径中一个顶点不能出现2次&#xff1f; DAG描述表达式&#xff1a; 算术表达式用树来表示&#xff0…...

力扣第157场双周赛

1. 最大质数子字符串之和 给定一个字符串 s&#xff0c;找出可以由其 子字符串 组成的 3个最大的不同质数 的和。 返回这些质数的 总和 &#xff0c;如果少于 3 个不同的质数&#xff0c;则返回 所有 不同质数的和。 质数是大于 1 且只有两个因数的自然数&#xff1a;1和它本身…...

青少年编程与数学 02-019 Rust 编程基础 19课题、项目发布

青少年编程与数学 02-019 Rust 编程基础 19课题、项目发布 一、准备工作1. 创建和配置项目2. 编写代码和测试3. 文档注释 二、构建发布版本1. 构建优化后的可执行文件2. 静态链接&#xff08;可选&#xff09; 三、发布到 crates.io1. Crates.io核心功能使用方法特点最新动态 2…...