C++ vtordisp的应用场景

news/2025/1/13 4:10:33/

文章目录

      • 问题代码
      • 1. 基本概念回顾
      • 2. 应用场景
        • 虚继承与虚函数并存的类层次结构
      • 3. 编译器相关考虑

问题代码

#include <iostream>
using namespace std;class base
{
public:base() {}virtual void show() { cout << "base:: show"<<endl; }
private:int ma;
};class derive:virtual public base
{
public:derive() {}virtual void show() { cout << "derive:: show"; }
private:int mb;
};int main()
{cout << sizeof(derive) << endl;
}

以上代码类大小常规来说应该是如下,占16个字节大小,但是为何是20呢
预期结构

class derive    size(16):+---0      | {vbptr}4      | mb+---+--- (virtual base base)8      | {vfptr}
12      | ma+---

实际结构,占大小20个字节

class derive    size(20):+---0      | {vbptr}4      | mb+---
8       | (vtordisp for vbase base)+--- (virtual base base)
12      | {vfptr}
16      | ma+---derive::$vbtable@:0      | 01      | 12 (derived(derive+0)base)derive::$vftable@:| -120      | &(vtordisp) derive::showderive::show this adjustor: 12
vbi:       class  offset o.vbptr  o.vbte fVtorDispbase      12       0       4 1

在这里插入图片描述
经过验证 必须满足以下两个条件

  1. 派生类重写了虚基类的虚函数。
  2. 派生类定义了构造函数或者析构函数。
    才会产生vtordisp.
    这就牵扯到vtordisp了,介绍如下

1. 基本概念回顾

在 C++ 中,当涉及虚继承时,为了确保在派生类对象中能正确定位虚基类的子对象(包含虚基类的数据成员、虚函数等内容),编译器会在派生类对象的内存布局中安排虚基类表指针等相关结构来记录偏移量信息,以实现准确访问虚基类部分。同时,对于有虚函数的类,会存在虚函数表(VTable)来支持多态调用。

vtordisp 主要用于处理虚继承和虚函数结合场景下,构造函数和析构函数中对虚基类指针调整的一种机制,它本质上是编译器为了正确处理对象的初始化和析构顺序、保证虚基类相关操作的正确性而引入的一个额外的字节(在 32 位系统下通常是 4 字节,64 位系统下通常是 8 字节)来存储偏移量相关信息。

2. 应用场景

虚继承与虚函数并存的类层次结构
  • 场景描述:当类层次结构中既有虚继承又有类自身包含虚函数的情况时,在派生类的构造函数和析构函数中,需要准确地处理与虚基类相关的初始化和清理工作,同时还要考虑虚函数机制带来的多态性影响。

3. 编译器相关考虑

  • 不同的编译器对于 vtordisp 的处理可能会有一些差异,有些编译器可能会根据具体的类层次结构复杂度、是否确实存在需要调整虚基类指针偏移量的情况等来决定是否启用 vtordisp 机制以及如何分配相应的字节来存储相关信息。比如在 Visual C++ 编译器中,对于符合特定条件的虚继承和虚函数结合的场景,会自动插入 vtordisp 相关代码来处理对象布局和操作顺序问题,而在 GCC 等其他编译器中,也有其对应的实现方式和判断标准来确保在类似场景下的代码正确性。

如果不想要vtordisp 可以加 #pragma vtordisp(off) 进行关闭。

vtordisp是Visual C++编译器的一个特性,主要用于解决在类继承中,虚函数的调用与对象布局的问题。当你在类中使用了虚函数,并且该类被继承,且继承类覆盖了基类的虚函数时,可能会出现所谓的"跳跃问题"(slicing problem)。

"跳跃问题"是指当你有一个基类的指针指向派生类对象,并且调用了虚拟函数,预期是派生类的函数被调用,但实际上可能会调用基类的函数。这是因为编译器为了能够快速地调用虚拟函数,直接使用了指针的偏移量来计算虚拟函数的地址,而不是检查实际对象的类型。

为了解决这个问题,当你在类中有一个或多个虚拟函数,并且类被继承,且派生类覆盖了基类的虚函数时,编译器可能会为类添加一个额外的隐藏成员,称为vtordisp字段。vtordisp字段的作用是在构造函数和析构函数执行过程中,记录对象的实际类型信息,以便正确地调用虚拟函数。具体由编译器进行管理。

在网上搜集资料并未搞清楚其底层原理,请知道的大佬不吝赐教。


http://www.ppmy.cn/news/1562699.html

相关文章

代码随想录算法训练营第三十二天|509.斐波那契数、70.爬楼梯、746.使用最小花费爬楼梯

目录 509.斐波那契数 动态规划五部曲&#xff1a; 1.确定dp数组&#xff08;dp table&#xff09;以及下标的含义 2.确定递推公式 3.dp数组如何初始化 4.确定遍历顺序 5.举例推导dp数组 70.爬楼梯 动态规划五部曲&#xff1a; 1.确定dp数组&#xff08;dp table&#xff09;…

unity免费资源2025-1-10

https://assetstore.unity.com/packages/3d/characters/humanoids/humans/streetwear-girl-2-8-casual-wear-girls-pack-3-274536 零元购码DAVIDGRETTE2025

AI绘画;Stable Diffusion再升级:学会以图生图!

前言 Stability AI 很高兴地宣布推出 Stable Diffusion Reimagine&#xff01;我们邀请用户通过 Stable Diffusion 尝试图像并“重新构想”他们的设计。 Stable Diffusion Reimagine 是一种新的 Clipdrop 工具&#xff0c;它允许用户无限制地生成单个图像的多个变体。无需复杂…

网络安全 | 网络安全法规:GDPR、CCPA与中国网络安全法

网络安全 | 网络安全法规&#xff1a;GDPR、CCPA与中国网络安全法 一、前言二、欧盟《通用数据保护条例》&#xff08;GDPR&#xff09;2.1 背景2.2 主要内容2.3 特点2.4 实施效果与影响 三、美国《加利福尼亚州消费者隐私法案》&#xff08;CCPA&#xff09;3.1 背景3.2 主要内…

Python|【Pytorch】基于小波时频图与SwinTransformer的轴承故障诊断研究

### Python|【Pytorch】基于小波时频图与SwinTransformer的轴承故障诊断研究 #### 引言 轴承作为机械设备中的关键部件&#xff0c;其运行状态直接影响到设备的整体性能和寿命。传统的故障诊断方法在处理非线性非平稳信号时存在困难&#xff0c;因此&#xff0c;提出一种更加…

多并发发短信处理(头条项目-07)

1 pipeline操作 Redis数据库 Redis 的 C/S 架构&#xff1a; 基于客户端-服务端模型以及请求/响应协议的 TCP服务。客户端向服务端发送⼀个查询请求&#xff0c;并监听Socket返回。通常是以 阻塞模式&#xff0c;等待服务端响应。服务端处理命令&#xff0c;并将结果返回给客…

#Phi-4:微软 14B 参数开源模型,性能匹敌 OpenAI GPT-4o-mini,现已登陆 Ollama

Phi-4&#xff1a;微软 14B 参数开源模型&#xff0c;性能匹敌 OpenAI GPT-4o-mini&#xff0c;现已登陆 Ollama 一、Phi-4 模型概述 &#xff08;一&#xff09;模型参数与规模 Phi-4 是微软推出的一款小型语言模型&#xff0c;拥有 140 亿参数。虽然参数量相对较小&#xf…

集合——数据结构

数据结构 就是计算机存储数据的方式。 不同情况下采取不同数据结构会让数据查找&#xff0c;存储更加有效率。 栈