C++中成员函数指针是如何实现的?

2024-05-03

C++中的成员函数指针分为三部分:

Offset
Address/index
virtual?

当使用派生对象调用时,偏移量用于指针调整base pointer.

这个抵消是如何实现的?它是否指向某个表,每个派生类都有一个表,并且该表包含以下形式的条目(base X, offset)?

另外,我可以在哪里获得有关此的更多信息?


首先,您应该注意到,C++ 方法可以像常规函数一样实现(并且通常实现),该函数在所有其他参数之前接受一个额外的隐藏参数,名为this.

换句话说在

struct P2d {
   double x, y;
   void doIt(int a, double b) {
       ...
   }
};

机器代码doIt与 C 编译器生成的结果相同

void P2d$vid$doIt(P2d *this, int a, double b) {
    ...
}

和一个像这样的电话p->doIt(10, 3.14)被编译为P2d$vid$doIt(p, 10, 3.14);

给定一个没有虚方法的简单类的方法指针can作为指向方法代码的常规指针来实现(注意:我正在使用vid“Void of Int+Double”作为 C++ 编译器为处理重载而进行的“名称修改”的玩具示例(具有相同名称但不同参数的不同函数)。

然而,如果类具有虚方法,则情况就不再正确了。

大多数 C++ 编译器使用 VMT 实现虚拟调度...即

struct P2d {
    ...
    virtual void doIt(int a, double b);
};

类似调用的代码p->doIt(10, 3.14) where p is a P2d *与 C 编译器生成的结果相同

(p->$VMTab.vid$doIt)(p, 10, 3.14);

即实例包含一个指向虚拟方法表的隐藏指针,该虚拟方法表的每个成员都包含有效代码地址(假设编译器无法推断出该类p确实是P2d而不是派生方法,因为在这种情况下,调用可以与非虚拟方法相同)。

方法指针需要尊重虚拟方法......即调用doIt间接使用派生实例上的方法指针P2d需要调用派生版本,而相同的方法指针在使用时则需要调用基本版本P2d实例。这意味着调用哪个代码的选择取决于指针和类实例。

一种可能的实现是使用蹦床:

void MethodPointerCallerForP2dDoit(P2d *p, int a, double b) {
    p->doIt(a, b);
}

在这种情况下,方法指针仍然只是指向代码的指针(但指向蹦床,而不是最终方法)。

另一种方法是将方法指针存储为index相反,VMT 内部的方法。这是可行的,因为在 C++ 中,方法指针绑定到特定的类,因此编译器知道该类是否有虚拟方法。

多重继承不会使方法指针的事情变得复杂,因为所有内容都可以在编译时解析为单个最终 VMT 表。

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

C++中成员函数指针是如何实现的? 的相关文章

  • 如何从更高级别启动用户级别的 Exe

    我希望一个进程始终在用户级别运行 当它由以管理员级别运行的安装程序 自定义 而不是 msi 启动时 或者当用户登录时 环顾四周 我不确定这是否可能 最简单的方法是有 2 个进程 一种是普通用户 它启动提升 管理进程 然后管理进程可以使用 I
  • 在单个 C# 泛型方法中返回可为 null 和 null?

    C 泛型方法是否可以返回对象类型或 Nullable 类型 例如 如果我有一个安全的索引访问器List我想返回一个值 稍后我可以使用以下任一方法检查该值 null or HasValue 目前我有以下两种方法 static T SafeGe
  • C 语言中的套接字如何工作?

    我对 C 中的套接字编程有点困惑 You create a socket bind it to an interface and an IP address and get it to listen I found a couple of
  • 确保 unsigned int/long 始终在 C# 中的检查上下文中执行

    有没有人觉得奇怪 uint 和 ulong 的默认上下文是未检查的 而不是检查的 因为它们旨在表示永远不能为负的值 因此 如果某些代码试图违反该约束 在我看来 自然且首选的行为是抛出异常 而不是返回最大值 这很容易使重要数据处于无效状态并且
  • 通过 TCP/.NET SSLStream 发送文件很慢/无法正常工作

    我正在编写一个与 SSL 配合使用的服务器 客户端应用程序 通过SSLStream 它必须做很多事情 不仅仅是文件接收 发送 目前 它的工作原理是 只有一个连接 我总是使用从客户端 服务器发送数据SSLStream WriteLine 并使
  • 起订量工作单元

    我是单元测试的新手 我想为我的搜索功能创建一个测试 我的服务层看起来像 public class EmployeeService BaseService IEmployeeService public EmployeeService IUn
  • 获取进程的所有 DLL

    我想获取为给定进程加载的所有 dll 的列表 我目前正在使用 NET框架4 0 我知道有一个bug https connect microsoft com VisualStudio feedback details 546430 syste
  • 关于 FirstOrDefault 或 SingleOrDefault

    FirstOrDefault 或 SingleOrDefault 将返回什么类型的数据 假设我的查询返回 3 条记录 例如 empid ename salary 1 joy 1500 2 rob 4500 3 jen 6500 所以如果我们
  • 获取RFC返回的嵌套结构的值?

    我是 C 新手 我有 rfc 它以嵌套结构的形式从 SAP 系统返回数据 但是当我使用以下方式获取该数据时 IrfcTable table rfc getTable exporting parameter et customer 它仅返回第
  • OpenMP 和 C++:this 指针

    Is thisOpenMP 中始终共享指针 尽管编译器不会抱怨以下代码default none pragma omp parallel for default none shared n for SInt i 0 i lt n i f i
  • 如何在控制台程序中获取鼠标位置?

    如何在 Windows 控制台程序中用 C 获取鼠标单击位置 点击时返回鼠标位置的变量 我想用简单的文本命令绘制一个菜单 这样当有人点击时 游戏就会注册它并知道位置 我知道如何做我需要做的一切 除了单击时获取鼠标位置 您需要使用 Conso
  • 当一种语言是另一种语言的平行超集时,这意味着什么?

    我正在阅读关于实时并发 C 的期刊文章 http link springer com article 10 1007 2FBF00365999 并且它在摘要中提到 因此你们中的任何人都可以通过该链接查看上下文 Concurrent C 是
  • 使用客户端 hello 消息进行 TLS 协议检测

    我需要检测网络流量中的 https 数据包 到目前为止 我将所有 443 标记为 https 但我不想再在这种情况下使用端口信息 检查客户端问候消息是否足够 Check 22 and version info 0300 0301 or 03
  • 如何获取数字列的确切类型,包括。规模和精度?

    有没有办法知道列中列的确切类型DataTable 现在我正在这样做 DataTable st dataReader GetSchemaTable foreach DataColumn col in st Columns var type c
  • 比较 C# 中的对象属性[关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 Locked 这个问题及其答案是locked help locked posts因为这个问题是题外话 但却具有历史意义 目前不接受新的答案或互动
  • 如何正确对齐 WPF GeometryGroup 中的路径?

    我正在使用一个GeometryGroup在圆的中心绘制一个符号 下面的示例显示了我在对此进行实验时的尝试之一 它具有从同一原点 32 32 出发的三条直线
  • 如何重写(重新实现)QFileSystemModel 中的成员函数

    我已经为此苦苦挣扎了一段时间 Qt s QFileSystemModel由于图标获取算法非常糟糕 在获取数百个文件时速度非常慢 我想完全禁用图标 它们被提取到QFileSystemModel data方法不是虚拟的 QFileSystemM
  • 在 C# 中设置风扇速度

    我知道以前有人问过这个问题 但我似乎无法让它发挥作用 我已调用以下内容 using System Management using System Management Instrumentation using System Runtime
  • 我可以创建一个 List> 吗?

    我正在尝试创建一个列表WeakReference使用 4 5 泛型实现 这样我就可以避免类型检查和转换WeakReference目标 但 WeakReference
  • Eclipse CDT C/C++:包含另一个项目的头文件

    我在 Eclipse CDT 中有两个 C 项目main and shared In shared我有一个名为calc h 我想在中使用这个标头main 所以我做了以下事情 added include calc h到相关文件main In

随机推荐

  • MySQL 索引创建速度很慢(在 EC2 上)

    我有一张相当简单的桌子 requestparams requestid varchar 64 NOT NULL requestString text ENGINE MyISAM 使用 LOAD DATA 填充表后 我正在更改架构并将 req
  • 如何安排函数在 Qt for Python 的主 UI 线程上运行?

    我正在移植一个 Python GTK 应用程序 因此它使用 Qt for Python PySide2 它使用Python标准实现工作线程threading模块和工作线程使用Gdk threads add idle 与主 GUI 线程交互
  • Jetty9 - Jetty 不是从单独的 {jetty.base} 运行

    在启动 jetty9 服务器作为服务时 我看到以下警告 我对此一无所知 警告 oejs HomeBaseWarning main Jetty 的此实例不是从单独的 jetty base 目录运行 不建议这样做 请参阅文档 http www
  • Case 表达式在 SQL 查询中无法正常工作

    我想连接列supplier使用逗号分隔符创建表并将其放入名为 contact 的别名字段中 我使用过检查空值的案例 假设如果contact number2则为空contact number3将在别名字段中 反之亦然 这是我的查询 SELEC
  • 如何将html设置为extjs中的元素

    1 如何设置HTML到已经创建的面板或任何其他元素 我是初学者 我尝试了下面的方法来设置 HTML 中的一些内容 var clickedElement Ext getCmp id el child gt clickedElement set
  • “排序文件名 | uniq”不适用于大文件

    我可以从小文本文件中删除重复条目 但不能从大文本文件中删除重复条目 我有一个 4MB 的文件 文件的开头如下所示 aa aah aahed aahed aahing aahing aahs aahs aal aalii aalii aali
  • 可扩展性和弹性有什么区别?

    我听说很多人交替使用这两个术语 但在我看来 它们之间还是有区别的 可扩展性 的能力软件系统在其当前硬件资源上处理更大的工作负载 scale up 或当前和额外的硬件资源 向外扩展 应用程序服务不中断 弹性 的能力硬件层下面 通常是云基础设施
  • 在命令行上编译 C++/CX

    我收到链接器错误fatal error C1107 could not find assembly platform winmd please specify the assembly search path using AI or by
  • 尝试构建我的 CUDA 程序时出现错误 MSB4062

    当我尝试构建我的第一个 GPU 程序时 出现以下错误 有什么建议可能会出什么问题吗 错误 1 错误 MSB4062 Nvda Build CudaTasks SanitizePaths 任务 无法从程序集 C Program 加载 文件 M
  • 如何处理 Ipython Notebook 中的引用?

    在 Ipython Notebook 中处理引用的最佳方法是什么 理想情况下 我想要一个 bibtex 文件 然后像在 Latex 中一样 在 Ipython markdown 单元格中拥有一个速记列表 并在笔记本末尾提供完整的参考文献 我
  • 截断浮点数而不向上舍入

    我有一个浮点数 我想将其截断为 3 位 但我不想向上舍入 例如 转换1 0155555555555555 to 1 015 not 1 016 我将如何在 Ruby 中做到这一点 您还可以转换为 BigDecimal 并对其调用 trunc
  • 为应用程序创建了新的 WidgetKit 扩展:SwiftUI 预览不适用于“appex 必须位于应用程序中”

    我使用的是 macOS 12 6 上的 Xcode 14 0 1 我正在尝试使用 WidgetKit 在现有应用程序中创建一个新的手表复杂功能 首先向我的项目添加一个 Widget 扩展模板目标 这会生成一个新文件夹 其中包含意图定义文件
  • UI 引导轮播第一张幻灯片不显示,然后在最后一张幻灯片崩溃

    我正在尝试实现 ui bootstraps 轮播 但是当页面加载时 第一个图像不会显示 但控件和指示器会显示 然后 当第二个图像显示时 我可以使用控件返回到第一个图像 它将显示正常 我可以使用控件到达最后一张幻灯片或让它自动滑动 但是当我到
  • 将 stdout 和 stderr 捕获到不同的变量中

    是否可以存储或捕获 stdout 和 stderr不同的变量 不使用临时文件 现在我这样做是为了获得标准输出out和标准错误err跑步时some command 但我会 喜欢避免临时文件 error file mktemp out some
  • Android 应用程序开发 - 不带 Intent 直接发送电子邮件

    任何人都可以建议我如何在不使用意图或打开另一个 Android 应用程序的情况下发送电子邮件 我希望点击发送按钮后直接发送电子邮件 我必须使用特定的 Office365 电子邮件来发送消息 我应该使用一些 API 或 SMTP 等吗 有没有
  • 通过浅复制避免 List 上的 ConcurrentModificationException

    我有一堂课如下 class Test private LinkedList
  • 如何导入名称与我的包中的模块冲突的模块?

    我的目录中有几个 python 模块 在同一目录下 我有一个包tests 我很想将模块命名为tests与它们包含测试的模块相同 尽管这当然并不重要 So in tests foo我天真地写着import foo 这不太好用 它是导入的tes
  • 如何将 Pixel 2 连接到 ADB

    我有一台已解锁并启用了 USB 调试的 Pixel 2 然而 如果我将其插入计算机 它只会显示正在充电 USB 线可以连接其他设备进行数据传输 但没有问题 所以它不是线 我可以轻松地将任何其他设备连接到我的任何端口 甚至是原来的 Pixel
  • 在 CodeIgniter 中使用 ajax 时出现 403 禁止错误

    我正在显示我的名字textbox使用 ajax 自动完成 但我的 ajax URL 不起作用 每次都显示在网络选项卡中 403 禁止 我尝试过像这样的ajax URL url baseUrl index php Employee contr
  • C++中成员函数指针是如何实现的?

    C 中的成员函数指针分为三部分 Offset Address index virtual 当使用派生对象调用时 偏移量用于指针调整base pointer 这个抵消是如何实现的 它是否指向某个表 每个派生类都有一个表 并且该表包含以下形式的