为什么即使对象指针在多重继承中不同,情况也是一样的?

2024-01-18

当使用多重继承时,C++ 必须维护多个 vtable,这导致对公共基类有“多个视图”。

这是一个代码片段:

#include "stdafx.h"
#include <Windows.h>

void dumpPointer( void* pointer )
{
    __int64 thisPointer = reinterpret_cast<__int64>( pointer );
    char buffer[100];
   _i64toa( thisPointer, buffer, 10 );
    OutputDebugStringA( buffer );
    OutputDebugStringA( "\n" );
}

class ICommonBase {
public:
    virtual void Common() = 0 {}
};

class IDerived1 : public ICommonBase {
};

class IDerived2 : public ICommonBase {
};

class CClass : public IDerived1, public IDerived2 {
public:
    virtual void Common() {
        dumpPointer( this );
    }
    int stuff;
};

int _tmain(int argc, _TCHAR* argv[])
{
    CClass* object = new CClass();
    object->Common();
    ICommonBase* casted1 = static_cast<ICommonBase*>( static_cast<IDerived1*>( object ) );
    casted1->Common();
    dumpPointer( casted1 );

    ICommonBase* casted2 = static_cast<ICommonBase*>( static_cast<IDerived2*>( object ) );
    casted2->Common();
    dumpPointer( casted2 );

    return 0;
}

它产生以下输出:

206968 //CClass::Common this
206968 //(ICommonBase)IDerived1::Common this
206968 //(ICommonBase)IDerived1* casted1
206968 //(ICommonBase)IDerived2::Common this
206972 //(ICommonBase)IDerived2* casted2

here casted1 and casted2具有不同的值,这是合理的,因为它们指向不同的子对象。当虚函数被调用时,到基类的转换已经完成,编译器不知道它最初是一个最派生的类。仍然this每次都一样。这是怎么发生的?


当在虚函数调用中使用多重继承时,对虚函数的调用通常会转到一个“thunk”,该“thunk”会调整this指针。在你的例子中,casted1指针的 vtbl 条目不需要 thunk 因为IDerived1的子对象CClass恰好与 CClass 对象的开始一致(这就是为什么casted1指针值与CClass object指针)。

但是,那casted2指向的指针IDerived2子对象与开头不一致CClass对象,所以vtbl函数指针实际上指向一个thunk而不是直接指向CClass::Common()功能。 thunk 调整this指向实际的指针CClass然后对象跳转到CClass::Common()功能。所以它总是会得到一个指向开始的指针CClass对象,无论它是从哪种类型的子对象指针调用的。

S里对此有很好的解释tanley Lippman 的《C++ 对象模型内部》一书 http://www.informit.com/store/product.aspx?isbn=0201834545,第 4.2 节“虚拟成员函数/MI 下的虚拟函数”。

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

为什么即使对象指针在多重继承中不同,情况也是一样的? 的相关文章

  • 没有强命名的代码签名是否会让您的应用程序容易被滥用?

    尝试了解authenticode代码签名和强命名 我是否正确地认为 如果我对引用一些 dll 非强命名 的 exe 进行代码签名 恶意用户就可以替换我的 DLL 并以看似由我签名但正在运行的方式分发应用程序他们的代码 假设这是真的 那么您似
  • 动态加载程序集的应用程序配置

    我正在尝试将模块动态加载到我的应用程序中 但我想为每个模块指定单独的 app config 文件 假设我的主应用程序有以下 app config 设置
  • 在结构中使用 typedef 枚举并避免类型混合警告

    我正在使用 C99 我的编译器是 IAR Embedded workbench 但我认为这个问题对于其他一些编译器也有效 我有一个 typedef 枚举 其中包含一些项目 并且我向该新类型的结构添加了一个元素 typedef enum fo
  • ASP.NET MVC:这个业务逻辑应该放在哪里?

    我正在开发我的第一个真正的 MVC 应用程序 并尝试遵循一般的 OOP 最佳实践 我正在将控制器中的一些简单业务逻辑重构到我的域模型中 我最近一直在阅读一些内容 很明显我应该将逻辑放在域模型实体类中的某个位置 以避免出现 贫血域模型 反模式
  • Asp.NET WebApi 中类似文件名称的路由

    是否可以在 ASP NET Web API 路由配置中添加一条路由 以允许处理看起来有点像文件名的 URL 我尝试添加以下条目WebApiConfig Register 但这不起作用 使用 URIapi foo 0de7ebfa 3a55
  • 使用实体框架模型输入安全密钥

    这是我今天的完美想法 Entity Framework 中的强类型 ID 动机 比较 ModelTypeA ID 和 ModelTypeB ID 总是 至少几乎 错误 为什么编译时不处理它 如果您使用每个请求示例 DbContext 那么很
  • 用于登录 .NET 的堆栈跟踪

    我编写了一个 logger exceptionfactory 模块 它使用 System Diagnostics StackTrace 从调用方法及其声明类型中获取属性 但我注意到 如果我在 Visual Studio 之外以发布模式运行代
  • 在 Windows 窗体中保存带有 Alpha 通道的单色位图会保存不同(错误)的颜色

    在 C NET 2 0 Windows 窗体 Visual Studio Express 2010 中 我保存由相同颜色组成的图像 Bitmap bitmap new Bitmap width height PixelFormat Form
  • OleDbDataAdapter 未填充所有行

    嘿 我正在使用 DataAdapter 读取 Excel 文件并用该数据填充数据表 这是我的查询和连接字符串 private string Query SELECT FROM Sheet1 private string ConnectStr
  • Clang 3.1 + libc++ 编译错误

    我已经构建并安装了 在前缀下 alt LLVM Clang trunk 2012 年 4 月 23 日 在 Ubuntu 12 04 上成功使用 GCC 4 6 然后使用此 Clang 构建的 libc 当我想使用它时我必须同时提供 lc
  • 不同枚举类型的范围和可转换性

    在什么条件下可以从一种枚举类型转换为另一种枚举类型 让我们考虑以下代码 include
  • 在 ASP.NET 5 中使用 DI 调用构造函数时解决依赖关系

    Web 上似乎充斥着如何在 ASP NET 5 中使用 DI 的示例 但没有一个示例显示如何调用构造函数并解决依赖关系 以下只是众多案例之一 http social technet microsoft com wiki contents a
  • SolrNet连接说明

    为什么 SolrNet 连接的容器保持静态 这是一个非常大的错误 因为当我们在应用程序中向应用程序发送异步请求时 SolrNet 会表现异常 在 SolrNet 中如何避免这个问题 class P static void M string
  • 如何在 C 中调用采用匿名结构的函数?

    如何在 C 中调用采用匿名结构的函数 比如这个函数 void func struct int x p printf i n p x 当提供原型的函数声明在范围内时 调用该函数的参数必须具有与原型中声明的类型兼容的类型 其中 兼容 具有标准定
  • 链接器错误:已定义

    我尝试在 Microsoft Visual Studio 2012 中编译我的 Visual C 项目 使用 MFC 但出现以下错误 error LNK2005 void cdecl operator new unsigned int 2
  • 通过指向其基址的指针删除 POD 对象是否安全?

    事实上 我正在考虑那些微不足道的可破坏物体 而不仅仅是POD http en wikipedia org wiki Plain old data structure 我不确定 POD 是否可以有基类 当我读到这个解释时is triviall
  • cmake 将标头包含到每个源文件中

    其实我有一个简单的问题 但找不到答案 也许你可以给我指一个副本 所以 问题是 是否可以告诉 cmake 指示编译器在每个源文件的开头自动包含一些头文件 这样就不需要放置 include foo h 了 谢谢 CMake 没有针对此特定用例的
  • 如何将带有 IP 地址的连接字符串放入 web.config 文件中?

    我们当前在 web config 文件中使用以下连接字符串 add name DBConnectionString connectionString Data Source ourServer Initial Catalog ourDB P
  • 将控制台重定向到 .NET 程序中的字符串

    如何重定向写入控制台的任何内容以写入字符串 对于您自己的流程 Console SetOut http msdn microsoft com en us library system console setout aspx并将其重定向到构建在
  • C# 成员变量继承

    我对 C 有点陌生 但我在编程方面有相当广泛的背景 我想做的事情 为游戏定义不同的 MapTiles 我已经像这样定义了 MapTile 基类 public class MapTile public Texture2D texture pu

随机推荐

  • 在显示表格单元格中使用边距[重复]

    这个问题在这里已经有答案了 我尝试在 li 中添加 margin left margin right 但它没有给它们之间留出空间 我应该添加什么来在列表之间留出一个空格 CSS btn top float right height 40px
  • Windows Azure 开发存储 Blob 服务未启动

    当我启动开发存储模拟器时 出现错误 The process cannot access the file because it is being used by another process 我猜这只发生在 BLOB 上 其他服务 即队列
  • 每次操作后的 MySQL SUM 和 MIN

    考虑以下表结构 Quantity BaseValue Id 0 3 1 1 0 8 1 2 0 5 1 3 0 2 1 4 假设这是一张表 名为Transactions 有什么方法可以对此表进行选择查询 它将对表中的值进行求和Quantit
  • Glibc 字符串操作函数的算法复杂度

    我意识到 Glibc 源代码经过了极其优化 并且是手工编码的汇编 是否有任何文档分析了常用字符串操作函数的算法复杂性 Big O 例如strmcp strncmp etc 可能没有这方面的文档 因为它很简单 其复杂度为 O n strcmp
  • 删除...创建与更改

    当涉及到创建存储过程 视图 函数等时 对对象执行 DROP CREATE 或 ALTER 哪个更好 我见过许多 标准 文档声称要执行 DROP CREATE 但我也见过许多提倡使用 ALTER 方法的评论和争论 ALTER 方法保留了安全性
  • 如何设置 HttpURLConnection 的内容类型?

    你知道如何设置吗Content Type on HttpURL连接 http developer android com reference java net HttpURLConnection html 以下代码适用于 Blackberr
  • 范围或地图返回什么?

    Go 有非常简洁的多返回值范例 但看起来像v ok map key and v k range m使用具有相同符号的不同机制 这是一个简单的例子 func f2 k v string return Hello World func main
  • Firebase - 应用程序分发无法获取应用程序信息:[403]调用者没有权限[重复]

    这个问题在这里已经有答案了 我正在使用 gradle 开发 Firebase App Distribution 我已经遵循了此中的所有步骤firebase 官方链接 https firebase google com docs app di
  • 修复 COM 引用:类型库导入程序无法转换成员 DISPPARAMS.rgvarg 的签名

    我有一个构建服务器 我在其中构建 Visual Studio 扩展 我最近迁移到另一台服务器 现在我收到以下警告 C Windows Microsoft NET Framework v4 0 30319 Microsoft Common t
  • 在 Eclipse 中调试时如何跳过 JRE 代码?

    在 Eclipse 中调试时 我单步执行 F5 语句 如下所示 encryptedBytes LightWeightEncryptor encrypt messageBytes password toCharArray 调试器进入 JRE
  • 从逗号分隔的字符串中批量插入

    我有一个表 其中一列包含以下数据 abc 2 2 34 5 3 2 34 32 2 3 2 2 def 2 2 34 5 3 2 34 32 2 3 2 2 我想获取这些数据并将其插入到另一个表中 使用逗号作为分隔符 就像您可以指定FIEL
  • C# TCP 套接字错误 - 10060

    我有一个 Windows 服务作为服务器 我以 localhost 作为客户端运行一个 Windows 窗体应用程序 这两个程序都使用 TCP 套接字连接来发送 接收数据 服务器侦听端口 8030 程序运行正常 但是 当我增强客户端程序以在
  • 在画布上手动逐像素绘制一个圆圈[关闭]

    Closed 这个问题需要细节或清晰度 help closed questions 目前不接受答案 我正在尝试做一些复杂的效果 为了做到这一点 我必须将其分解为各个组件 我可以在此基础上进行构建 并希望它们能够组合在一起 现在在画布上画一个
  • 浏览器将边框值截断为整数

    每当非整数像素值用于元素的边框时 浏览器都会将该值截断为整数 为什么会这样呢 我知道边境不会actually占用像素的一部分 但这些类型的值有时与其他值结合使用以形成完整像素 例如 宽度为 1 6px 的左右边框应导致元素的总宽度增加 3p
  • Console.Clear() 闪烁

    while true Console Clear for int row 0 row lt 50 row for int col 0 col lt 50 col Console Write world row col Console Wri
  • 当原始对象更改时,绑定不会更新

    我想我误解了 Angular 中数据绑定和作用域的工作原理 或者我对 Javascript 有一些误解 我希望有人能帮助我 假设我有一个工厂 它有一个对象 并为其定义了一个 getter setter app factory myFacto
  • Tkinter 滚动条不滚动

    我正在尝试创建一个带有两个画布和一个滚动条的图形用户界面 同时穿过这两个画布 作为另一个项目的测试 我创建了根 两个画布 并使用网格方法将一些标签固定到每个画布上 并创建了滚动条 但是 当我运行该程序时 滚动条会移动 但窗口的内容根本没有改
  • 在 Java 中管理 XAdES 签名的库 [关闭]

    Closed 此问题正在寻求书籍 工具 软件库等的推荐 不满足堆栈溢出指南 help closed questions 目前不接受答案 我正在寻找一个允许创建和验证 XAdES 签名的 Java 库 格式越多越好 XAdES BES XAd
  • 二维unordered_map

    typedef boost unordered map
  • 为什么即使对象指针在多重继承中不同,情况也是一样的?

    当使用多重继承时 C 必须维护多个 vtable 这导致对公共基类有 多个视图 这是一个代码片段 include stdafx h include