用于多重虚拟继承和类型转换的虚拟表和虚拟指针

2024-01-12

我对 vptr 和内存中对象的表示有点困惑,希望你能帮助我更好地理解这个问题。

  1. 考虑B继承自A并且都定义了虚函数f()。据我所知,B类对象在内存中的表示如下:[ vptr | A | B ]vtbl that vptr指向包含B::f()。我还了解到从B to A除了忽略之外什么也不做B位于对象末尾的部分。这是真的吗?这种行为难道不是错误的吗?我们想要该类型的对象A执行A::f()方法而不是B::f().

  2. 有没有几个vtables系统中有多少类?

  3. 如何将一个vtable从两个或多个类继承的类是什么样子的? C的对象在内存中如何表示?

  4. 与问题 3 相同,但具有虚拟继承。


以下对于 GCC 来说是正确的(对于 LLVM 来说似乎也是正确的)link https://llvm.org/docs/CompilerWriterInfo.html#abi),但对于您正在使用的编译器也可能如此。所有这些都依赖于实现,并且不受 C++ 标准管辖。然而,GCC编写了自己的二进制标准文档,安腾ABI http://static.coldattic.info/cxx-abi/abi.html.

我尝试用更简单的语言解释虚拟表如何布局的基本概念,作为我的一部分关于 C++ 中的虚函数性能的文章 http://coldattic.info/post/3/,您可能会发现这很有用。以下是您的问题的答案:

  1. 描述对象内部表示的更正确方法是:

    | vptr | ======= | ======= |  <-- your object
           |----A----|         |
           |---------B---------|
    

    B contains它的基类A,它只是在结束后添加了一些他自己的成员。

    铸造自B* to A*确实什么也没做,它返回相同的指针,并且vptr保持不变。但是,简而言之,虚函数并不总是通过 vtable 调用。有时它们的调用方式与其他函数一样。

    这是更详细的解释。您应该区分调用成员函数的两种方式:

    A a, *aptr;
    a.func();         // the call to A::func() is precompiled!
    aptr->A::func();  // ditto
    aptr->func();     // calls virtual function through vtable.
                      // It may be a call to A::func() or B::func().
    

    问题是众所周知在编译时该函数将如何被调用:通过 vtable 或只是一个通常的调用。事情是这样的转换表达式的类型在编译时已知,因此编译器在编译时选择正确的函数。

    B b, *bptr;          
    static_cast<A>(b)::func(); //calls A::func, because the type
       // of static_cast<A>(b) is A!
    

    在这种情况下,它甚至不查看 vtable 内部!

  2. 一般来说,不会。如果一个类继承自多个基类,则该类可以拥有多个虚函数表,并且每个基类都有自己的虚函数表。这样的一组虚拟表形成一个“虚拟表组”(参见第 3 部分)。

    类还需要一组构造 vtable,以便在构造复杂对象的基类时正确分配虚拟函数。您可以进一步阅读我链接的标准 http://static.coldattic.info/cxx-abi/abi.html#vtable-ctor.

  3. 这是一个例子。认为C继承自A and B,每个类定义virtual void func(), 也a,b or c虚函数与其名称相关。

    The C将有一个由两个 vtable 组成的 vtable 组。它将与以下对象共享一个 vtable:A(当前类自己的函数所在的vtable称为“primary”),以及一个vtableB将附加:

    | C::func()   |   a()  |  c()  || C::func()  |   b()   |
    |---- vtable for A ----|        |---- vtable for B ----| 
    |--- "primary virtual table" --||- "secondary vtable" -|
    |-------------- virtual table group for C -------------|
    

    对象在内存中的表示形式看起来几乎与它的虚函数表相同。只需添加一个vptr在组中的每个 vtable 之前,您将粗略估计数据在对象内部的布局方式。您可以在相关部分 http://static.coldattic.info/cxx-abi/abi.html#layoutGCC 二进制标准。

  4. 虚拟库(其中一些)布置在 vtable 组的末尾。这样做是因为每个类应该只有一个虚拟基,如果它们与“通常的”虚函数表混合在一起,那么编译器就无法重用构造的虚函数表的一部分来生成派生类的虚函数表。这将导致计算不必要的偏移并降低性能。

    由于这样的放置,虚拟基地还在其 vtable 中引入了附加元素:vcall此处定义的每个虚拟函数的偏移量(当从完整对象内的虚拟基指针跳转到覆盖虚拟函数的类的开头时,获取最终覆盖程序的地址)。每个虚拟基地还添加vbase偏移量,插入到派生类的 vtable 中;它们允许找到虚拟基址的数据开始的位置(它不能被预编译,因为实际地址取决于层次结构:虚拟基址位于对象的末尾,并且从开始的移位取决于有多少个非虚拟基址)当前类继承的类。)。

Woof,我希望我没有引入太多不必要的复杂性。无论如何,您可以参考原始标准,或您自己的编译器的任何文档。

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

用于多重虚拟继承和类型转换的虚拟表和虚拟指针 的相关文章

  • 打击垃圾邮件机器人

    我的网站中有 C 表单 希望防止垃圾邮件机器人填写它 诀窍是 我想避免 CAPTHA 或任何其他用户输入 以避免丢失单个注册 以下是我心中的一些技巧 隐藏输入栏 问题 这还有效吗 跟踪时间 从第一个用户输入 关注名字 到发布表单 人类需要
  • 仅使用扩展方法在 Linq 中进行漂亮、干净的交叉连接 [重复]

    这个问题在这里已经有答案了 可能的重复 使用扩展方法表示的嵌套 from LINQ 查询 https stackoverflow com questions 9115675 nested from linq query expressed
  • 分层架构中的异常处理

    我们正在分层设计中重构 当然还有重新设计 我们的服务 我们有服务操作层 BLL 网络抽象层 gt 处理网络代理 数据抽象层 但我们对我们的异常处理策略有点困惑 我们不想向外界透露太多 BLL 的信息 从其他层到bll就可以了 我们不想让 t
  • 双线性序列给出奇数结果

    我试图让我的表现技能 不存在 达到标准 但在将公式写入代码时遇到了问题 这是我试图将其引用为 转换 为代码的公式 考虑一个序列 u 其中 u 定义如下 号码u 0 1是第一个u 对于每个x in u then y 2 x 1 and z 3
  • 对静态成员变量的未定义引用

    我有一个有静态成员的类 它也是我的程序中其他几个类的基类 这是它的头文件 ifndef YARL OBJECT HPP define YARL OBJECT HPP namespace yarlObject class YarlObject
  • 使用 JSON 格式正确配置 NLog 到 IHostBuilder

    我有以下代码 应该接受 NLog 的 JSON appsettings 配置 然后使用它来创建 NLog LogFactory 这个 NLog 工厂应该被传递到 MyService 类中 以便在那里创建一个记录器 class Program
  • 在不使用 ncurses 的情况下用 C/C++ 编写“真正的”交互式终端程序,例如 vim、htop...

    不 我不想使用ncurses 因为我想了解如何 终端可以工作 并且我自己编程也很有趣 没有 必须是可移植的 它必须只能在基于 linux xterm 的终端仿真器上工作 我想做的是编写一个交互式终端应用程序 例如 htop 和 vim 我的
  • 如何使用boost库读取和写入.ini文件[重复]

    这个问题在这里已经有答案了 如何使用boost库读取和写入 或修改 ini文件 With Boost PropertyTree您可以读取并更新树 然后写入文件 请参阅load and save功能 看一下如何访问属性树中的数据 http w
  • 使用 size_t 值反向遍历向量

    我想以相反的方向遍历向量的值 如您所知 向量的大小为 size t 当我使用以下代码时 for size t r m size 1 r gt 0 r x r f r for size t c r 1 c lt m size c x r m
  • C for 循环索引:新 CPU 中的前向索引更快吗?

    在我订阅的邮件列表上 两位知识渊博的 IMO 程序员正在讨论一些优化的代码 并说了以下内容 在 5 8 年前发布的 CPU 上 向后迭代 for 循环稍微快一些 e g for int i x 1 i gt 0 i 因为比较i归零比将其与其
  • ASP.NET MVC 路由 - 向路由添加 .html 扩展名

    我对 MVC 和路由非常陌生 我被要求修改一个应用程序以使用不同的 url 由于我没有经验 这项任务对我来说有点困难 好吧 让我们谈谈一些代码 routes MapRoute CategoryBySeName Route name prod
  • Visual Studio Code 调试默认 ASP.NET Core MVC WebApp:不起作用

    我正在使用 Manjaro linux 并尝试调试默认的 ASP NET Core MVC 项目 但调试停止 没有任何错误 我创建了该项目 dotnet new mvc in a Meow文件夹 没什么特别的 然后添加了新的配置 NET C
  • 使用 QGraphicsScene 实现流畅的动画

    我希望我的问题并不总是同样的问题 我有一个 QGraphicsScene 它的项目是一些 QGraphicsPixmap 我用一个计时器来移动它们 每秒 SetX 10 我设置 10是因为窗口大100 使用这个解决方案我的动画不流畅 我想我
  • printf() 使用字符串表“解码器环”调试库

    我写这封信是想看看你们中是否有人见过或听说过我即将描述的想法的实现 我有兴趣为嵌入式目标开发 printf 风格的调试库 目标非常遥远 并且我和目标之间的通信带宽预算非常紧张 因此我希望能够以非常有效的格式获取调试消息 通常 调试语句如下所
  • 该组件没有由 uri 标识的资源

    我想创建一个通用数据网格以在我的所有视图 用户控件上使用 这是我的结构 Class Library called Core Class called ViewBase public class ViewBase UserControl pu
  • TreeView:仅在子节点中存在复选框

    我需要一个树视图控件 根节点没有复选框 只有图像 所有子节点都有一个复选框 图像 C net 2 0 winforms 不是 wpf WinForms树视图默认不支持混合复选框 非复选框节点 您可以在树视图上全局启用复选框 并使用以下命令在
  • 为什么我不能对普通变量进行多态?

    我是一名Java程序员 最近开始学习C 我对某事感到困惑 据我了解 在 C 中 要实现多态行为 您必须使用指针或引用 例如 考虑一个类Shape与实施的方法getArea 它有几个子类 每个子类都以不同的方式重写 getArea 然后考虑以
  • OpenGL 计算着色器调用

    我有一个与新计算着色器相关的问题 我目前正在研究粒子系统 我将所有粒子存储在着色器存储缓冲区中 以便在计算着色器中访问它们 然后我派遣一个一维工作组 define WORK GROUP SIZE 128 shaderManager gt u
  • 在 C# WinForms 中预览文档(Word、Excel、PDF、文本文件等)?

    我正在开发一个 C WinForms 应用程序 我希望能够 预览 其中的各种文档类型 也就是说 当用户从列表中选择文件名时 它会在下面以相同的形式显示所选文件的预览 这很像 Outlook 允许您无需双击即可预览选定邮件的方式 有没有什么方
  • C# amo 获取角色完整

    我正在开发一个 SSAS 项目 其中除其他事项外 我需要获取 C 中表格多维数据集的完整用户列表 目前我让它以这样的方式工作 我可以获得角色 但数据不完整 当我调用 Server Database Roles 为了便于阅读而简化 属性并枚举

随机推荐

  • 正则表达式至少匹配一个字符或一个空格

    我正在使用以下正则表达式来找出检测至少一个字符 b a zA Z0 9 1 现在我还需要探测空间 我怎样才能做到这一点 您可以使用以下方法检测正则表达式中的空格 s 该标记将捕获字符串中的任何空格 在您的正则表达式中 您可以包含此标记 s括
  • 会话/实体管理器已关闭

    我有这个 Hibernate dao 在我的本地机器上测试时它运行良好 但对于某些交易它会抛出IllegalStateException 我相信这是因为多个用户同时点击它 我可能是错的 更新支付道 Repository public cla
  • 修改PIN中的申请指令

    我正在使用英特尔 PIN 来修改我的应用程序中的指令 我使用此链接中的 Safecopy 示例作为参考 https software intel com sites landingpage pintool docs 81205 Pin ht
  • Prolog列表有未实例化的尾部,需要去掉它

    我正在开发 Prolog 程序 它产生正确的输出 一个列表 但该列表末尾有一个未实例化的变量 我做错了事 并且不知道如何摆脱它 这是代码 plaatsingen plaatsingen Prod Hoev Rest Order Plaats
  • 使用 awk sed 解析更新 puppet 文件

    我有一个包含多行代码的木偶文件 其中有一个部分如下所示 defaultrepo myrepo defaultbranch mybranch gitmod pullstuff othergitcode gitcommit gt b54123b
  • 为什么 C++20 中 unique_ptr 不是 equal_comparable_with nullptr_t ?

    使用 C 20concept我注意到std unique ptr似乎无法满足std equality comparable with
  • 转置 data.table

    数据计算结束后有效转换 data table 的好方法是什么 nrow 500e3 ncol 2000 m lt matrix rnorm nrow ncol nrow nrow colnames m lt c foo seq ncol 1
  • 还原并反应不需要的效果

    大家好 我正在尝试使用 redux 来制作购物车功能 2 问题描述 问题是 一旦我想从我的购物篮中删除不是最后一个的产品 Redux 确实从商店中删除了所需的产品 但在前端我仍然可以看到该产品 并且 React 会从列表中删除最后一个产品
  • 用于语义相似性的 BERT 嵌入

    我之前发布过这个question https stackoverflow com questions 60767089 bert get sentence level embedding after fine tuning 我想获得与此类似
  • 为什么要使用 Mockito? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我是 Mockito 的新手 我已经开始学习它了 但我有一些问题 为什么我们需要使用 Mockito 据我所知 它用于模拟 创建虚拟对
  • 我可以指望这个 ASP.NET 事件日志源始终被注册吗?

    未处理的异常导致基于 ASP NET 的应用程序在 NET Framework 2 0 中意外退出 http support microsoft com id 911816让我认为使用以下约定命名的事件日志源将始终在安装了 NET Fram
  • Spring 与 Spring Boot 集成 SFTP 示例

    我们正在为 Spring 应用程序使用最新的 Spring Boot 并为 SFTP 使用最新的 Spring Integration 我访问过 Spring Integration SFTP 文档站点 并按原样采用了 Spring Boo
  • Thread.sleep() 永远不会返回

    我有一个奇怪的错误Thread sleep 关于Java 由于某种原因 当我在某些机器上调用 sleep 时 它永远不会返回 我无法弄清楚是什么导致了这种行为 起初 我认为错误可能在我的代码中的其他地方 所以我做了最简单的睡眠测试 publ
  • 卡托皮县的县边界

    如何在 Cartopy 中绘制美国县边界 绘制州和国家边界非常简单 ax add feature cfeature BORDERS with scale 50m ax add feature cfeature STATES with sca
  • CakePHP 会话 ID 路径或其他共享 url 结果的方法 - 欢迎推荐

    我正在寻找有关合理的 Cake 方法的建议 以创建基于会话 id 的 url 我可以与其他人共享该 URL 以查看与我所看到的相同的搜索结果 我知道在标准 php 中 我只需获取会话 id 并将其传递给 url 但我猜测 Cake 可能有一
  • javascript选择输入事件

    我正在尝试从 javascript 创建一个选择输入 并在用户更改选项时绑定一个函数 到目前为止我有 filter change function console log CHANGED 但选择其他东西后什么也不会发生 这段代码有什么问题
  • 为什么 PHP 开发人员无法根据线程范围提供 setlocale 函数

    We have 设置语言环境 http php net manual en function setlocale phpPHP 中的函数 该函数有警告信息 区域设置信息是按进程维护的 而不是按线程维护的 如果您在多线程服务器 API 例如
  • 如何阻止任何滑块向 URL 添加主题标签

    任何滑块都会添加哈希标签 例如 panel1 1在网址末尾 I tried hashtags false但它不起作用 有没有其他方法可以阻止它生成这些主题标签 尝试将其更改为hashTags false 注意标签中的大写 T
  • 如何使用 podfile 中的源?

    我是ios开发新手 由于某种原因 我需要为我的 Cordova 应用程序手动设置 podfile 有GoogleCloudMessaging and GGLInstanceID在我的podfile中 现在我想安装一个brightcove视频
  • 用于多重虚拟继承和类型转换的虚拟表和虚拟指针

    我对 vptr 和内存中对象的表示有点困惑 希望你能帮助我更好地理解这个问题 考虑B继承自A并且都定义了虚函数f 据我所知 B类对象在内存中的表示如下 vptr A B 和vtbl that vptr指向包含B f 我还了解到从B to A