具有“空类”的 C++ 多重继承内存布局

2023-11-26

我知道多重继承的内存布局没有定义,所以我不应该依赖它。但是,在特殊情况下我可以依赖它吗?也就是说,一个类只有一个“真正的”超类。所有其他都是“空类”,即既没有字段也没有虚拟方法的类(即它们只有非虚拟方法)。在这种情况下,这些附加类不应向该类的内存布局添加任何内容。 (更简洁地说,在 C++11 的措辞中,该类有标准布局)

我可以推断所有超类都没有偏移吗?例如。:

#include <iostream>

class X{

    int a;
    int b;
};

class I{};

class J{};

class Y : public I, public X,  public J{};

int main(){

    Y* y = new Y();
    X* x = y;
    I* i = y;
    J* j = y;

    std::cout << sizeof(Y) << std::endl 
                  << y << std::endl 
                  << x << std::endl 
                  << i << std::endl 
                  << j << std::endl;
}

Here, Y是班级X是唯一真正的基类。程序的输出(在使用 g++4.6 的 Linux 上编译时)如下:

8

0x233f010

0x233f010

0x233f010

0x233f010

正如我的结论,没有指针调整。但是这个实现是特定的还是我可以依赖它。即,如果我收到一个类型的对象I(而且我知道只存在这些类),我可以使用reinterpret_cast将其投射到X?

我希望我可以依赖它,因为规范规定对象的大小必须至少是一个字节。因此,编译器无法选择其他布局。如果会布局的话I and J成员背后X,那么它们的大小将为零(因为它们没有成员)。因此,唯一合理的选择是将所有超类无偏移地对齐。

如果我使用reinterpret_cast,我是正确的还是在玩火?I to X here?


在 C++11 中,编译器需要使用空基类优化标准布局类型。看https://stackoverflow.com/a/10789707/981959

对于您的特定示例,所有类型都是标准布局类,并且没有公共基类或成员(见下文),因此您可以依赖该行为in C++11(实际上,我认为许多编译器已经遵循了该规则,当然 G++ 也遵循了该规则,其他编译器也遵循了安腾 C++ ABI.)

警告:确保您没有任何相同类型的基类,因为它们必须位于不同的地址,例如

struct I {};

struct J : I {};
struct K : I { };

struct X { int i; };

struct Y : J, K, X { };

#include <iostream>

Y y;

int main()
{
  std::cout << &y << ' ' << &y.i << ' ' << (X*)&y << ' ' << (I*)(J*)&y << ' ' << (I*)(K*)&y << '\n';

}

prints:

0x600d60 0x600d60 0x600d60 0x600d60 0x600d61

对于类型Y只有其中之一I基数可以在偏移量为零处,所以尽管X子对象位于偏移量零处(即offsetof(Y, i)为零)和其中之一I基址位于同一地址,但另一个I基数(至少对于 G++ 和 Clang++)是对象中的一个字节,所以如果你有一个I*你不能reinterpret_cast to X*因为你不会知道which I它指向的子对象I在偏移量 0 或I在偏移量 1 处。

编译器把第二个放进去就可以了I偏移量 1 处的子对象(即inside the int) 因为I没有非静态数据成员,因此您实际上无法取消引用或访问该地址处的任何内容,只能获取指向该地址处的对象的指针。如果您将非静态数据成员添加到I then Y将不再是标准布局并且不必使用 EBO,并且offsetof(Y, i)将不再为零。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

具有“空类”的 C++ 多重继承内存布局 的相关文章

  • 将运算符 << 添加到 std::vector

    我想添加operator lt lt to std vector
  • 如何在 VC++ CString 中验证有效的整数和浮点数

    有人可以告诉我一种有效的方法来验证 CString 对象中存在的数字是有效整数还是浮点数吗 Use tcstol http msdn microsoft com en us library w4z2wdyc aspx and tcstod
  • 尝试了解使用服务打开对话框

    我已经阅读了有关使用 mvvm 模式打开对话框的讨论 我看过几个使用服务的示例 但我不明白所有部分如何组合在一起 我发布这个问题寻求指导 以了解我应该阅读哪些内容 以更好地理解我所缺少的内容 我将在下面发布我所拥有的内容 它确实有效 但从我
  • C# 方法重载决策不选择具体的泛型覆盖

    这个完整的 C 程序说明了这个问题 public abstract class Executor
  • Environment.CurrentDirectory 与 System.IO.Directory.GetCurrentDirectory

    我正在编写一个 Net WinForms 并不断在调试和发布配置之间切换 并且有一些文件我需要任一配置才能访问 我想做的是将文件放在 BIN 文件夹中的公共目录中 这样它看起来像这样 MyProject Bin CommonFiles My
  • 前向声明类型和“已声明为类类型的非类类型”

    我对以下代码有问题 template
  • 未找到 Boost 库,但编译正常

    我正在尝试在 C 中使用 boost 的文件系统 使用时看起来编译没问题 c c Analyse c o Analyse o g W Wall L usr local lib lboost filesystem lboost system
  • 如何将 .txt 文件中的数据转换为 xml? C#

    我在一个文本文件中有数千行数据 我想通过将其转换为更容易搜索的内容来轻松搜索 我希望 XML 或其他类型的大型数据结构 尽管我不确定它是否是最好的对于我的想法 每行的数据如下所示 第 31 册 托马斯 乔治 32 34 154 每本书都不是
  • 如何在 C# Designer.cs 代码中使用常量字符串?

    如何在 designer cs 文件中引用常量字符串 一个直接的答案是在我的 cs 文件中创建一个私有字符串变量 然后编辑 Designer cs 文件以使用此变量 而不是对字符串进行硬编码 但设计者不喜欢这样抛出错误 我明白为什么这行不通
  • Eigen 和 OpenMP:由于错误共享和线程开销而没有并行化

    系统规格 Intel Xeon E7 v3 处理器 4 插槽 16 核 插槽 2 线程 核心 Eigen 系列和 C 的使用 以下是代码片段的串行实现 Eigen VectorXd get Row const int j const int
  • 如何将AVFrame转换为glTexImage2D使用的纹理?

    如您所知 AVFrame 有 2 个属性 pFrame gt data pFrame gt linesize 当我从视频 sdcard test mp4 android平台 读取帧后 并将其转换为RGB AVFrame副 img conve
  • 从 C# 使用 Odbc 调用 Oracle 包函数

    我在 Oracle 包中定义了一个函数 CREATE OR REPLACE PACKAGE BODY TESTUSER TESTPKG as FUNCTION testfunc n IN NUMBER RETURN NUMBER as be
  • 如果输入被重定向则执行操作

    我想知道如果我的输入被重定向 我应该如何在 C 程序中执行操作 例如 假设我有已编译的程序 prog 并且我将输入 input txt 重定向到它 我这样做 prog lt input txt 我如何在代码中检测到这一点 一般来说 您无法判
  • 不可变类与结构

    以下是类与 C 中的结构的唯一区别 如果我错了 请纠正我 类变量是引用 而结构变量是值 因此在赋值和参数传递中复制结构的整个值 类变量是存储在堆栈上的指针 指向堆上的内存 而结构变量作为值存储在堆上 假设我有一个不可变的结构 该结构的字段一
  • C++ - 多维数组

    处理多维数组时 是否可以为数组分配两种不同的变量类型 例如你有数组int example i j 有可能吗i and j是两种完全不同的变量类型 例如 int 和 string 听起来您正在寻找 std vector
  • 将 Word 转换为 PDF - 禁用“保存”对话框

    我有一个用 C 编写的 Word 到 PDF 转换器 除了一件事之外 它工作得很好 有时 在某些 Word 文件上 后台会出现一条消息保存源文件中的更改 gt 是 否 取消 但我没有对源文件进行任何更改 我只想从 Word 文件创建 PDF
  • WPF DataGrid / ListView 绑定到数组 mvvm

    我们假设你有 N 个整数的数组 表示行数的整数值 在模型中 该整数绑定到视图中的 ComboBox Q1 如何将数组 或数组的各个项目 绑定到 DataGrid 或 ListView 控件 以便 当您更改 ComboBox 值时 只有那么多
  • 了解 Lambda 表达式和委托 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我已经尝试解决这个问题很长一段时间了 阅读在线博客和文章 但到目前为止还没有成功 什么是代表 什么是 Lambda 表达式 两者的优点
  • 在 Win32 控制台应用程序中设置光标位置

    如何在 Win32 控制台应用程序中设置光标位置 最好 我想避免制作句柄并使用 Windows 控制台功能 我花了整个早上沿着那条黑暗的小巷跑 它产生的问题比它解决的问题还要多 我似乎记得当我在大学时使用 stdio 做这件事相对简单 但我
  • EntityFramework 6.0.0.0 读取数据,但不插入

    我创建了一个基于服务的数据库 folderName gt Add New Item gt Data gt Service based Database文件到 WPF 应用程序中 然后我用过Database First方法并创建了Person

随机推荐

  • 如何用Java计算某人的年龄?

    我想在 Java 方法中以 int 形式返回以年为单位的年龄 我现在所拥有的是以下内容 其中 getBirthDate 返回一个 Date 对象 带有出生日期 public int getAge long ageInMillis new D
  • 如何等待elasticsearch重新索引?

    我有一个ElasticSearch带索引posts设置好的了 我会时不时地向其推送新文档 I want ElasticSearch仅当所有文档均已编制索引时才回复我的查询 我怎样才能做到这一点 在 ES 2 中 您可以调用refresh A
  • SQLITE:如果共享列,则将行合并为单行

    从上一篇文章中 我在 sqlite3 中有以下视图 CREATE View AttendeeTableView AS SELECT LastName FirstName as AttendeeName CompanyName PhotoUR
  • 编译器对虚函数调用的优化

    说明为什么虚拟分派在运行时发生的最流行的例子是当无法在编译时确定将创建哪个派生类时 例如 Base b rand 2 1 new Derived1 new Derived2 或者当它取决于用户输入时 假设情况并非如此 并且可以在编译时完全确
  • 如何使用实体框架查询外键对象?

    我正在尝试了解 Entity Framework 6 但遇到了一个问题 我已经能够在测试项目中重现该问题 A Movie has a Nameand a Revenue A Revenue has a GrossIncome public
  • “clear”是Javascript中的保留字吗?

    我只是花了很长时间才弄清楚我不应该使用clear 作为Javascript中函数的名称 Hello br
  • Winform另存为

    有谁知道任何文章或网站显示如何在 win 表单中创建 另存为 对话框 我有一个按钮 用户单击并序列化一些数据 然后用户使用此 另存为 框指定他们希望将其保存的位置 你的意思是像SaveFileDialog 来自MSDN示例 稍作修改 usi
  • C++ - 从文件读取到双精度[关闭]

    Closed 这个问题不符合堆栈溢出指南 目前不接受答案 我对编程还比较陌生 目前正在学习 C 课程 到目前为止我还没有遇到任何重大问题 我正在制作一个程序 其中 X 数量的评委可以打出 0 0 10 0 双倍 的分数 然后删除最高和最低的
  • 用 NSURLSession 替换 NSURLConnection

    我已经开始设计NetworkCommunication 我有一个设计NSOperation子类创建并管理自己的NSURLConnection The NSOperation子类由一个实例化NetworkManger类将其添加到NSOpera
  • 在 shell 脚本中读取 python 变量?

    我的 python 文件有这两个变量 week date 01 03 16 01 09 16 cust id 12345 我如何将其读入接受这两个变量的 shell 脚本中 我当前的 shell 脚本需要手动编辑 dt 和 id 我想将 p
  • 如何使用express-graphql抛出多个错误?

    在express graphql应用程序中 我有一个userLogin像这样的解析器 const userLogin async id password context info gt if id throw new Error No id
  • MongoDB:$elemMatch和$and在数组内查找对象有什么区别?

    查询运算符的使用有逻辑上的区别吗 and db collection find and array field1 someValue array field2 3 以及投影算子的用法 elemMatch db collection find
  • 在 JavaScript 中生成特定范围内的随机整数

    如何在 JavaScript 中生成两个指定变量之间的随机整数 例如x 4 and y 8将输出任何4 5 6 7 8 上面有一些例子Mozilla 开发者网络 page Returns a random number between mi
  • 如何在编译时填充NSArray?

    在 Objective C 中 如何做类似的事情是 int array 1 2 3 4 纯C语言 我需要用 NSString 填充 NSArray 并尽可能减少开销 代码和 或运行时 不可能像在编译时那样创建数组 那是因为它不是 编译时间常
  • chrome PDF 查看器无法下载文件

    这是我的情况 我有一个运行 PDF 生成器的服务器 当我使用一些参数发出请求时 它会返回一个 PDF 文件 该 PDF 不会存储在运行时生成的服务器中 Everything goes fine I can get the PDF open
  • 尽管我已经安装了该模块,为什么我在 VS Code 中收到“ModuleNotFoundError”?

    我正在尝试使用 VS Code 调试一些 python 代码 我收到以下关于我确定已安装的模块的错误 Exception has occurred ModuleNotFoundError No module named SimpleITK
  • 以编程方式将 TypeScript 字符串编译为 Javascript 字符串

    有没有办法编译一个String在其 JavaScript 中包含 TypeScriptString相等的 例如 在 Coffeescript 以及 LiveScript coco 等 中 它是一个 简化的 单行代码 jsCompiledCo
  • 如何在Makefile中运行子Shell脚本?

    我想执行 Shell 命令 但我不知道如何在 Makefile 中正确执行子 bash 命令 import bd while nc z make ips awk mysql print 2 3306 do sleep 1 done 感谢您的
  • 如何计算两个地理/GPS 坐标之间的角度?

    我有两个 GPS 坐标 例如 纬度 1 经度 1 和 纬度 2 经度 2 谁能帮我找到这两点之间的角度 值应为 0 360 度 取自this以前的帖子 float dy lat2 lat1 float dx cosf M PI 180 la
  • 具有“空类”的 C++ 多重继承内存布局

    我知道多重继承的内存布局没有定义 所以我不应该依赖它 但是 在特殊情况下我可以依赖它吗 也就是说 一个类只有一个 真正的 超类 所有其他都是 空类 即既没有字段也没有虚拟方法的类 即它们只有非虚拟方法 在这种情况下 这些附加类不应向该类的内