C++:在多重继承时的指针转换问题

C++多重继承和基类地址 C++支持多重继承,比如 class Derived : public Base1, public Base2 {     … };   我们熟知的基类指针强转成继承类指针的用法是这样子的: base *p1 = … // 实际指向derived object derived *p2 = (derived *)p1; 或者运行时转换,需要打开编译选项rtti derived *p 阅读详情

   原文链接:http://www.chineselinuxuniversity.net/articles/59183.shtml

在C++中,指针的类型转换是经常发生的事情,比如将派生类指针转换为基类指针,将基类指针转换为派生类指针。指针的本质其实就是一个整数,用以记录进程虚拟内存空间中的地址编号,而指针的类型决定了编译器对其指向的内存空间的解释方式。

  基于上面的理解,我们似乎可以得出一个结论,C++中对指针进行类型转换,不会改变指针的值,只会改变指针的类型(即改变编译器对该指针指向内存的解释方式),但是这个结论在C++多重继承下是 不成立的。

  看下面一段代码:

  #include <iostream>

  using namespace std;

  class CBaseA

  {

  public:

  char m_A[32];

  };

  class CBaseB

  {

  public:

  char m_B[64];

  };

  class CDerive : public CBaseA, public CBaseB

  {

  public:

  char m_D[128];

  };

  int main()

  {

  auto pD = new CDerive;

  auto pA = (CBaseA *)pD;

  auto pB = (CBaseB *)pD;

  cout << pA << '\n' << pB << '\n' << pD << endl;

  cout << (pD == pB) << endl;

  }

  这段代码的输出是:

  0x9f1080

  0x9f10a0

  0x9f1080

  1

  可以看出,指向同一个堆上new出来的内存指针,在经过类型转换之后,其值会发生改变。究其原因,要从C++中多重继承的内存布局说起。

  new CDerive;执行之后,生成的内存布局如下:

  同时我们注意到,pB与pD的指针差值正好是CBaseA占用的内存大小32字节,而pA与pD都指向了同一段地址。这是因为,将一个派生类的指针转换成某一个基类指针,编译器会将指针的值偏移到该基类在对象内存中的起始位置。

  可是为什么C++要这样设计呢?

  试想,沿用上面的场景,如果pB和pA都指向对象的首地址,那么使用pB指针来定位CBaseB的成员变量m_B时,编译器应该将pB指针偏移32个字节,从而跳过CBaseA的内存部分。而pB指针如果是这样产生的auto pB = new CBaseB;,那么使用pB指针来定位CBaseB的成员变量m_B时,偏移量应该为0。

  关键在于对于一个指针而言,编译器不关心也无法知道该指针的来源(一种极端情况,指针是从其他模块传递过来的),而只是把它视为一个有指针类型的整数。所以对于CBaseB类型的指针,取CBaseB的成员变量m_B时,偏移量应该通通为0,这是通过CBaseB的类声明就可以统一决策的事情。

  说到这里,pD和pB的指针地址为什么不一样大家应该清楚了,可是为什么下面的代码输出是1呢?

  cout << (pD == pB) << endl;

  输出1表示pD和pB是相等的,而刚刚我们才说明了,pD和pB的地址是相差了32个字节的。

  其实这也是编译器为大家屏蔽了这种指针的差异,当编译器发现一个指向派生类的指针和指向其某个基类的指针进行==运算时,会自动将指针做隐式类型提升已屏蔽多重继承带来的指针差异。因为两个指针做比较,目的通常是判断两个指针是否指向了同一个内存对象实例,在上面的场景中,pD和pB虽然指针值不等,但是他们确确实实都指向了同一个内存对象(即new CDerive;产生的内存对象 ),所以编译器又在此处插了一脚,让我们可以安享==运算的上层语义。


   原文链接:http://www.chineselinuxuniversity.net/articles/59183.shtml

《深入探索C++对象模型》指针赋值时的隐式偏移详解 在C++多重继承中,当派生类指针(或对象)被转换为非主基类(非第一个基类)的指针时,编译器会自动调整指针的地址,使其指向目标基类子对象在内存中的实际位置。这一过程称为隐式偏移调整 阅读详情

相关推荐

基于LangGraph的智能报告生成平台项目分析

不知道你是否知道或者了解OpenAI and Gemini Deep Research。他们是一种能够根据输入问题进行规划、结合网络搜索获取信息并最终呈现结果的研究工具或技术。那这样research是如何实现的呢?最近刚好看到一个实现类似功能的开源项目: open_deep_search。本文将基于该项目进行代码层面剖析。

u011160113的博客 923

当C++多继承遇上类型转换

1 由来 客户用陈旧的VC++6.0进行项目开发,有一块功能需要我来实现。让一个早就习惯了VS2013的人去使用C++支持不太好的VC6去做开发实在是非常不爽,于是另辟蹊径,打算使用VC++2013开发编译出DLL,供VC6下调用即可。使用C++开发DLL的基本原则是减少暴露和接口简单化,最常用的方式就是使用纯虚类导出接口。另一种就是使用C++实现,但是导出时只导出C函数。处于使用的便利性考虑,

smstong的成长轨迹 7671

[华为ensp]双核心的园区网

(给部分只会emm......借鉴的朋友提个醒,在group-member e0/0/2 to e0/0/20是所选,所以到了p l t那会给2-20端口都配置上trunk,别紧张,不是你问题)完成上述配置后,PC1可以ping通HTTP2服务器,Client1可以访问HTTP2服务器的HTTP站点,如果不能就要检查上述是否正确。本次实验主要目的是采用双核心的冗余网络,采用MSTP和VRRP技术,在核心层交换机上配置SC1上配置OSPF协议。SC1交换机上配置VRRP。在SC1上配置DHCP。

2301_78859499的博客 1416

c++学习之多重继承指针强转父类

当子类实例指针被强转为父类指针时,指针的值会发生变化,根据c++标准对象的概念,以该父类指针调用同名成员函数,调用的是子类的函数。为了做到这点,在强转时,),以使其指向该父类的虚表。

qq_26962739的博客 537

别再为Word转PDF表格变形发愁了!Aspose.Words for Java 19.5 保姆级避坑指南

本文详细介绍了使用Aspose.Words for Java 19.5解决Word转PDF时表格变形问题的完整方案。从格式转换原理到实战技巧,涵盖固定表格宽度、禁用自动调整、强制文本换行等核心方法,并提供高级场景应对策略和性能优化建议,帮助开发者高效处理复杂文档转换需求。

weixin_28702105的博客 266

把 ABAP 采购订单增强做成一条可控流水线:BAdI ME_PROCESS_PO_CUST 全流程实战

摘要: SAP MM模块的ME_PROCESS_PO_CUST BAdI提供了采购订单全生命周期的增强点,覆盖从ME2*N事务到BAPI调用的各类场景。该接口通过INITIALIZE、OPEN、PROCESS_*系列方法、CHECK等组成完整处理流水线,支持字段控制、业务校验、数据派生等功能。关键注意事项包括:PROCESS_*方法仅在相关对象变更时触发、字段控制需区分参考键与动态规则、避免递归调用等。该BAdI采用面向对象设计,通过IF_PURCHASE_ORDER_*等接口操作采购单据对象,而非直接修改

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 402

C++多重继承子类和父类指针转换过程中的一个易错点

这两天有个C++新手问了我一个问题,他的工程当中有一段代码执行不正确,不知道是什么原因。我调了一下,代码如果精简下来,大概是下面这个样子: class IBaseA { public: virtual void fnA() = 0; int m_nTestA; }; class IBaseB { public: virtual void...

weixin_30342209的博客 535

DSP篇--C6678功能调试系列之SPI调试

SPI传输数据分为线上直接收发和通过EDMA的数据传输两种。第一种是直接将数据放在线上(SPIDAT1),在寄存器(SPIBUF)中写入命令实现数据的收发;第二种需要配置EDMA,将数据buffer直接作为EDMA的数据源进行传输,其需要配置的参数和中断与EDMA一致。

nanke_yh的博客 1258

C++多重继承下的指针类型转换

在C++中,指针的类型转换是经常发生的事情,比如将派生类指针转换为基类指针,将基类指针转换为派生类指针。指针的本质其实就是一个整数,用以记录进程虚拟内存空间中的地址编号,而指针的类型决定了编译器对其指向的内存空间的解释方式。 基于上面的理解,我们似乎可以得出一个结论,C++中对指针进行类型转换,不会改变指针的值,只会改变指针的类型(即改变编译器对该指针指向内存的解释方式),但是这个结论在C+

chinabinlang的专栏 9716

[RK3568 Android11] 开发之蓝牙(AP6275S)

前言 蓝牙是一种支持设备短距离通信(一般10m内)的无线电技术,能在包括移动电话、PDA、无线耳机、笔记本电脑、相关外设等众多设备之间进行无线信息交换。利用“蓝牙”技术,能够有效地简化移动通信终端设备之间的通信,也能够成功地简化设备与因特网Internet之间的通信,从而数据传输变得更加迅速高效,为无线通信拓宽道路。 接下来是在RK3568上调试AP6275S模块蓝牙部分: 一、设备树dts配置 根据硬件原理图,找到对应的控制引脚,配置好dts: ...

~未来可期~ 4072

YOLO11,ultralytics-main源代码目录结构详解

本文详细介绍了YOLO11框架的ultralytics-main源代码目录结构,帮助用户更好地理解和使用YOLO模型。主要目录包括:docker文件夹,包含多种Docker镜像文件,适用于不同硬件环境;docs文件夹,存放YOLO的说明文档;examples文件夹,提供YOLO使用的示例代码;tests文件夹,包含单元测试模块;ultralytics文件夹,为核心代码所在,包含推理逻辑、配置、数据处理等模块。其中,engine文件夹负责训练和推理引擎,models文件夹存放模型架构,nn定义神经网络结构

qq_30279827的博客 1282

C++多重继承的指针问题

下面说说C++多重继承中关于指针的一些问题。指针指向问题 先看下面的程序:class Base1 { public: virtual void fun1() {cout << "Base1::fun1" << endl;}; };class Base2 { public: virtual void fun2() {cout << "Base2::fun1" << endl;}; }

给永远比拿愉快 3523

内模控制(IMC)——理论、应用与实践

内模控制方法的核心思想是利用被控对象的数学模型(即内模)构建控制器,使得控制器可以“预知”被控系统的动态响应,从而在控制输入中提前补偿模型的固有特性和扰动影响。常见的内模控制结构中,将系统分为无延迟部分和扰动部分,并利用内部模型预测输出值,再通过反馈回路进行误差修正。utuimctufbtutui​mctuf​bt其中,uimctu_imc(t)ui​mct为内模预测得到的预补偿控制量,ufbtu_fb(t)uf​bt。

闲人编程的博客 2631

删除父类指针

文章目录问题学习问题1解决方法参考 问题 1.删除父类指针这个操作是否可行?如何才是可行的? 2.有没有内存泄漏? 学习 测试代码: class VA { public: ~VA() { cout << "~VA()..." << endl; } virtual void virFunc() = 0; }; class VA1 { p

pkxpp的专栏 918

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

深入理解C++继承与多态

如图,假如我们定义了A,B两个类,而类B同时也拥有包含了类A的ma,mb,mc三个成员变量,直接一点,我们可以在类B中再定义ma,mb,mc三个成员变量,但这样不仅会导致代码的大量重复,而且这样也并不能表示B中包含的是A中的三个成员变量。为了解决这种问题,面向对象的编程设计了继承操作(如图class B:public A)表示B类继承了A类,A称为,B称为。

2603_95759313的博客 994

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

C++多重继承下的指针类型转换 图解

在C++中,指针的类型转换是经常发生的事情,比如将派生类指针转换为基类指针,将基类指针转换为派生类指针。指针的本质其实就是一个整数,用以记录进程虚拟内存空间中的地址编号,而指针的类型决定了编译器对其指向的内存空间的解释方式。 基于上面的理解,我们似乎可以得出一个结论,C++中对指针进行类型转换,不会改变指针的值,只会改变指针的类型(即改变编译器对该指针指向内存的解释方式),但是这个结论在C+

happyjxt的专栏 1324

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

C++多重继承与void*指针转换问题

C++支持多重继承,然而多重继承可能会导致一些奇怪的问题,我前段时间遇到一个指针转换问题,非常典型。

安晓辉生涯——聚焦程序员的职业规划与成长 4919

C++多层继承与多重继承父类指针转换以及注意事项

无论是多层继承还是多重继承,都支持父类指针指向子类对象(向上转型),这是多态的基础。多层继承的核心注意事项是:虚析构、成员访问范围、向下转型安全性。多重继承需额外关注:成员二义性、菱形继承的虚继承解决、指针地址偏移问题。合理使用父类指针可以简化代码(如用统一的父类指针容器管理不同子类对象),但需根据继承结构的复杂性针对性规避风险。

u010632343的博客 1056

C++多重继承:威力、陷阱与现代最佳实践全景解析

本文深入探讨C++多重继承机制,分析其作为"双刃剑"的特性。文章系统性地介绍了多重继承的语法本质、内存布局和经典菱形继承问题,重点讲解了虚继承的解决方案及其性能代价。同时指出了多重继承在接口组合、Mixin模式和策略设计中的合理应用场景,并提供了替代方案选择指南。针对现代C++发展,文章总结了多重继承的优化约束和使用准则,强调应谨慎但不必妖魔化这一特性,建议优先用于纯接口继承场景,并注重代码文档和团队共识。通过平衡灵活性与复杂性,开发者可充分发挥多重继承在构建高内聚系统架构中的价值。

聚焦前沿科技与硬核技术底层拆解,深耕 AI、量子计算、WebAssembly 等核心领域,拒绝碎片化科普。以通俗语言讲透复杂原理,用干货内容拆解技术逻辑,助力从业者吃透核心、把握趋势,每篇都是可落地的深度技术沉淀。 1895

实验:C++中有继承关系类型间指针强制转换行为的正确性

目标 我在使用C++时经常有“将一个子类指针转换为基类指针,再在需要时转换为子类指针”的行为。大多时候没发现问题,以至于让我产生错觉: “觉得只要确实是一个子类对象,那么不管其指针类型如何在基类与子类间转换,都不会出问题” 。而这一错觉让我在最近一个牵扯到多重继承的环境下,指针转换出现了问题。 因此我想专门对这一问题做些实验,本篇的目标是: 实验在各种情况下指针强制转换行为是否能保证正确性。 在实验与思考的过程中,我从《C++多重继承下的指针类型转换 - 敲代码的小阿狸 - 博客园》中得到些提示。 实验

主要记录了工作之余胡乱学习的知识,大部分是入门级别的内容。 主要是为了自己未来有用到时能快速上手,相当于是个备忘录。 当然,也很开心其他人可以从中找到对自己有用的信息。^_^ 1796

【c/c++】多重继承时的内存模型

今天查 bug 时遇到一种情况。有一个c++对象发生了 use after free。这个对象涉及的业务比较复杂,并且有算法在里面,因此想定位 bug 是比较困难的。因此,我们在几个关键的节点,把这个指针地址打印了出来。两个关键的位置是当 bug 复现时,根据 use after free 报出的指针地址,发现在所有的构造函数打印的 this 指针都没有。于是我怀疑这个指针的差异跟对象的多重继承有关。于是我找了相近的指针。果然有一个指针与它相差8个字节。

weixin_43233774的博客 1102

多重继承下父子类之间的类型转换

文章目录一、前言二、情景模拟复现三、开始分析1. 情况12. 情况23. 情况34. 情况4四、运行结果五、总结 一、前言 在日常工作中踩了一个坑,现象是:从一个dll里获取导出类A,然后调用类A的FunA,结果FunA没有被调用,相关代码简化如下: class AImpl : public OtherClass, public A { // OhterClass 不包含类A的FunA ... // 用户通过该函数获取A的指针,结果用A的指针调用FunA失败 void Query(

Quellaaa的博客 1568

C++中的多重继承

C++中的多重继承 虽然在软件设计中,许多书籍都推荐优先使用组合而不是继承,然而继承仍然拥有许多天然的优势,对基类成员的自动拥有,而不用像组合要显示地去转向调用所需复用的成员,从而平添更多的代码。 多重继承在某些情况下,可以使我们的设计具有更多的灵活性,下面我们讨论一些多重继承中的问题及解决办法。   我们实现了一个抽象基类A,然后由此派生了出了诸多的实现类,如A1,A2,A3,在项目的起初,这些

追逐我的梦 专栏 1934

C++:多重继承

MI描述的是有多个直接基类的类。与单继承一样,公有MI表示的也是is-a关系。例如,Worker派生出Singer和Waiter,再从Singer和Waiter派生出SingingWaiter。但多重继承会带来许多问题,最主要的两个便是就上述两个问题,下面根据举例Worker继承给出相关解决方法。

2401_86107325的博客 1014
上一篇: C++多线程编程简单实例
下一篇: C++中类对象所占空间的大小
静水若流深
博客等级 码龄14年 5粉丝 12原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值