c++基础知识之父类地址和基类地址一定相同?

C++ 类继承:构造函数与析构函数调用顺序,派生类和基类之间的特殊关系,公有继承及其他 文章目录一、派生类构造函数与基类构造函数二、创建与销毁派生类对象时,构造函数和析构函数的调用三、派生类和基类之间的特殊关系四、公有继承(一)、何为公有继承(二)、多态公有继承(三)、虚函数的工作原理(四)、虚函数注意事项五、访问控制:protected六、抽象基类 一、派生类构造函数与基类构造函数 派生类的构造函数做了如下事情: 创建基类对象 派生类构造函数通过成员初始化列表将基类信息传递给基类... 阅读详情

背景

hi,粉丝朋友们:
大家好!这两天在分析智能指针Refbase相关内容时候,debug打印相关记录一直有个颠覆我观念的问题一直让我无比纠结。
本质原因可能还是java代码的思维去理解c++导致的。
情况如下:
java代码

public class  A {
	func() {
		Log.i("this= " +this )
	}
}

public class B extends A {
	func1() {
		Log.i("this= " +this )
	}
}

如果new B(),那么java中调用func和func1,打印的this指针肯定都是同一个

同样以这个思想去套c++,认为c++也一样。

具体问题

调试LayerHandle类时候
frameworks/native/services/surfaceflinger/FrontEnd/LayerHandle.h

class LayerHandle : public BBinder

发现是继承BBinder

class BBinder : public IBinder

BBinder又是继承IBinder

class IBinder : public virtual RefBase

IBinder又继承RefBase

这种层级较多,不过层级多不影响分析,我们用java思维当然可以认为RefBase里面的this和LayerHandle类中使用的this是同一个。

所以加如下打印:

LayerHandle::LayerHandle(const sp<android::SurfaceFlinger>& flinger,
                         const sp<android::Layer>& layer)
      : mFlinger(flinger), mLayer(layer), mLayerId(static_cast<uint32_t>(layer->getSequence())) {
              ALOGE(" LayerHandle::LayerHandle() %p getDebugName %s",this,mLayer->getDebugName());
      }

注意这里LayerHandle构造加了打印this地址

同样在Refbase本身因为有相关的地址打印:

void RefBase::incStrong(const void* id) const
{
    ALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
}

是不是可以认为这里RefBase在incStrong of后面打印的this肯定和上面的LayerHandle打印的this一样?因为LayerHandle本身是RefBase的孙子类。

下面来看结果:

03-10 21:51:58.668   350   429 E SurfaceFlinger:  LayerHandle::LayerHandle() 0x73366d342210 getDebugName Surface(name=8fea5e0 StatusBar)/@0x22305c5 - animation-leash of insets_animation#132

可以看到LayerHandle的this地址是0x73366d342210

看看RefBase的打印


03-10 21:51:58.668   350   429 D RefBase : incStrong of 0x73366d342240 from 0x73366d342210: cnt=268435456

明显看到incStrong of 后面是0x73366d342240明显和0x73366d342210是有一定偏移的,不相等

这个是为啥????难道子类指针还和基类的指针不是一个东西,是分别指向两个对象?

验证是否真的不一样:

鉴于LayerHandle各种可能比较复杂考虑写个简单一些类来验证,看看难道子类和基类指针真的不一样?

class WeightClass : public RefBase
{  
public:  
        virtual void testVirtual();
        void printRefCount()  
        {   
        }  
};  

class StrongClass :  public WeightClass  //注意这里普通继承
{  
public:  
        StrongClass()  
        {  
                        ALOGW("Construct StrongClass Object. %p\n",this);  
        }  

        virtual ~StrongClass()  
        {  
        }
        void testVirtual() {

        }  
};  
void TestStrongClass(StrongClass* pStrongClass)  
{  
        sp<StrongClass> test = sp<StrongClass>::make();

}  
int main(int argc, char** argv)  
{  
        StrongClass* pStrongClass = new StrongClass();  
        TestStrongClass(pStrongClass);  
}
03-10 23:24:29.360  2482  2482 W weightpointer: Construct StrongClass Object. 0x781b7af54450

StrongClass Object对象的this打印为0x781b7af54450,RefBase中相关打印:

03-10 23:24:29.360  2482  2482 D RefBase : incStrong of 0x781b7af54450 from 0x781b7af54450: cnt=268435456

可以看到incStrong of 0x781b7af54450的this打印确实和 StrongClass Object的一模一样

那么问题来了?为啥上面的LayerHandle的this就是和Refbase的this不一样呢?

经过验证查询发现继承方式上有一点差别:

class IBinder : public virtual RefBase

这里的IBinder继承时候采用是virtual继承方式,那么我们来尝试修改成这个方式试试?

转变成虚继承方式:

class WeightClass : public RefBase
{  
public:  
        virtual void testVirtual();
        void printRefCount()  
        {   
        }  
};  

class StrongClass : virtual public WeightClass  //注意这里变成虚继承
{  
public:  
        StrongClass()  
        {  
                        ALOGW("Construct StrongClass Object. %p\n",this);  
        }  

        virtual ~StrongClass()  
        {  
        }
        void testVirtual() {

        }  
};  
void TestStrongClass(StrongClass* pStrongClass)  
{  
        sp<StrongClass> test = sp<StrongClass>::make();

}  
int main(int argc, char** argv)  
{  
        StrongClass* pStrongClass = new StrongClass();  
        TestStrongClass(pStrongClass);  
}

变成虚继承后的打印如下:

03-10 21:52:02.877  2270  2270 W weightpointer: Construct StrongClass Object. 0x728c48faa700
03-10 21:52:02.877  2270  2270 D RefBase : incStrong of 0x728c48faa708 from 0x728c48faa700: cnt=268435456

明显可以看到StrongClass的this地址 0x728c48faa700但是RefBase的地址是0x728c48faa708
果然不一样了。

虚继承相关知识:

这个属于c++里面比较少见基础知识:
https://blog.youkuaiyun.com/effort_study/article/details/119488496

更多framework干货请关注“千里马学框架”

Windows 本地安装 OpenClaw(龙虾)完整教程(纯净无广告) 《Windows系统OpenClaw本地AI网关安装指南》 本文提供Windows 10/11系统下OpenClaw(龙虾)AI网关的完整部署教程,包含: 环境配置:Node.js安装验证 核心安装:npm全局部署OpenClaw 模型对接:以DeepSeek为例配置API 扩展功能:飞书机器人集成方法 日常管理:启停命令/Web面板访问 卸载清理:完整移除服务与残留 教程涵盖初始化配置、技能管理、常见问题排查,特别说明管理员权限要求及飞书配对流程,适合新手30分钟内完成本地AI网关搭建。通过命令行操作与W 阅读详情

相关推荐

手把手教你用示波器搞定PCIe 5.0 REFCLK时钟信号测量(附完整参数解读)

本文详细介绍了如何使用示波器进行PCIe 5.0 REFCLK时钟信号测量,包括示波器与探头的选择、关键参数的测量方法及解读,以及实战中的常见问题与解决方案。通过手把手教学和完整参数解读,帮助硬件工程师高效完成时钟信号测量,确保系统稳定性。

weixin_28704565的博客 359

C++基础之多态虚表中我一直的误区!

之前我的认识: 子类继承拥有虚函数的父类,并且没有重写虚函数 ----子类的虚表地址与父类虚表地址相同 代码: _vfptr:虚表的地址 由此可见,虚表地址pE的是0x01162100,pF的是0x01162108

Eden's space 1335

【加密社】私钥碰撞器,秒杀市面上的碰撞器

基于上述的逻辑和代码,开发了ETH挖掘器(图1.1)这里有个亮点是:1.很多开发者在判断地址是否有效的环节上,用的是查询余额,其实这是不对的,查询余额你可能只能查询对应代币的余额,例如usdt,eth等但是如果用查询交易次数就不一样了,你只要是交易过,我就认为是有效钱包,这样的速度比查询余额要快,也要更准确。2.rpc节点可配置。

加密社的博客 1581

C++多继承中的this指针

根据输出,证明了我们的猜想,共用的永远都是第一个继承对象,后面的对象在调用的时候编译器应该是会自动转换this地址的。可以看见对象A和C是公用的一个地址,由此我们推断多继承与第一个对象共用地址,修改顺序,再来看输出。这里就可以想到有虚函数多继承公用virtul table的例子,原理应该也是这样。在C++继承中其中一个父类会与子类公用一个地址,本文字探索究竟公用的哪一个地址。废话不多说,直接上代码。

小木子先生的博客 500

磁悬浮轴承控制策略设计及性能对比

摘要:针对高速磁悬浮转子控制问题,本文提出多方案对比分析。建立含陀螺效应的5自由度动力学模型,分析陀螺耦合、质量不平衡等关键挑战。对比四种控制策略:基础PID解耦、交叉反馈+自适应陷波、H∞鲁棒+前馈补偿、滑模控制+观测器,从实时性、鲁棒性等维度评估优劣。推荐采用交叉反馈+H∞+自适应陷波的混合方案,通过内环电流环与外环位置环协同,实现陀螺效应动态解耦和扰动抑制。实施步骤包括系统辨识、控制器设计、硬件部署等,需配合实验验证与参数整定。该方案综合性能最优,适用于高转速、强扰动场景。

技术工作者 1775

【2026-Spark实验一-Windows中安装Spark环境】

本文详细介绍了在Windows系统中配置Spark 3.5.8开发环境的完整流程。主要内容包括:安装JDK 8并配置环境变量,下载并解压Spark 3.5.8预编译版,设置SPARK_HOME系统变量,配置Hadoop的winutils工具解决Windows兼容性问题。通过spark-shell和SparkPi示例程序验证环境配置成功,确保Spark能够正常运行分布式计算任务。文中特别强调了路径命名规范、环境变量设置顺序等关键细节,提供了完整的配置截图和验证方法,帮助开发者快速搭建稳定的Spark学习环境。

pblh123的专栏 1587

谈谈基类与子类的this指针(C++)

记得孙鑫VC++视频教程里有一段剖析MFC的代码,大意就是 CTESTAPP类是CWINAPP的子类,而CTESTAPP创建一个全局对象时,在CWINAPP的构造函数里面用了this指针,但是这里this指针指向的的是CTESTAPP的对象,而不是所在类的对象,也许读者这时候对这个this指针有点糊涂了! 不要怕!马上让你明明白白! 请看下面一段代码: #incl

专注 机器学习+人工智能 7521

ROS探索篇(一)在Gazebo中实现移动机器人仿真与环境搭建

$x+y=z$

weixin_52029211的博客 4621

父类的指针指向子类的地址,调用的方法是父类的还是子类的?

从地址上来分析,父类和子类的指针所包含的都是子类的地址,那他们的调用可能是存在优先级的,这样的优先级如何去看,去判断呢

zbmax001的专栏 920

深入探索 ClickHouse:性能优化之道

在大数据处理的广袤天地里,ClickHouse 宛如一颗璀璨的明星,以其卓越的性能为海量数据的存储与查询提供了强大助力。但要想让 ClickHouse 发挥出极致效能,性能优化至关重要。今天,就让我们一同深入探寻 ClickHouse 的性能优化之路。

arnold66的专栏 1547

VMware使用Windows、WinXP等虚拟机上不了网的解决办法(管用)

这个情况一般出现在可以插网线的电脑上,比如台式机和有网线插口的笔记本。需要转换器才能插网线的笔记本一般不会出现这种情况. 查看主机的IP地址和虚拟机的IP地址是否在同一网段,如果在的话,虚拟机就能上网了!!(备注:虚拟机中的IP地址一定要和主机中的用来上网的那个连接的IP地址相同哦)。

爱吃雪糕的小布丁的博客 1万+

C++ 虚继承、虚基类指针、虚基类表

当一个类有虚基类时,编译器需要额外的指针来解析虚基类的偏移,从而支持动态多态。的大小可能导致对齐问题(例如,它可能是 4 字节,而后续成员需要 8 字节对齐),编译器插入。计算所需的存储空间,并决定对象的内存分布,即便还没有实际分配对象。,表明该类可能包含指针(通常为 8 字节,在 64 位系统上)和一些数据成员。生成,可用于分析 C++ 类的内存布局和虚拟继承机制的实现。这幅图片展示了 C++ 代码的编译结果,分析的是一个。的情况下,帮助对象正确解析虚基类的存储位置。类的内存布局,并报告。

xinxin的博客 1209

《QT+PCL》点云配准进阶——GROR配准

GROR点云配准

阁楼 1318

c++基础知识3以及类和对象上

嗨喽,大家好呀,今天给大家带来的是我们c++基础知识最后一弹,以及初识我们的类和对象,下面让我们开始学习吧!

2401_83052144的博客 907

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

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

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

11. C++空基类优化

我们都知道,在C++中,不存在大小是零的类。即便是空类,也要占据一个字节,否则无法比较两个空类对象是否是同一个对象(在C/C++中,默认使用地址来判断两个变量是否是同一个)。即便这两个对象有相同的基类,但毕竟是不同的对象,如果指向了同一个地址,那么就无法通过地址来区分对象。其中,1和3是硬性限制,无法突破,但2问题是可以解决的。卖个关子,欲知详情,请见下期。如果仍然像之前说的那种内存等效模型,那么编译器会每个空基类对象都分配内存,因此即便。的大小是2,符合本期开篇提出的继承体系中的内存模型,可等效为。

谢谢大家的关注 1343

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

C++中为什么要引入抽象基类和纯虚函数?

为什么要引入抽象基类和纯虚函数?主要目的是为了实现一种接口的效果。 抽象类是一种特殊的类,它是为了抽象和设计的目的为建立的,它处于继承层次结构的较上层。 ⑴抽象类的定义:带有纯虚函数的类为抽象类。 ⑵抽象类的作用: 抽象类的主要作用是将有关的操作作为结果接口组织在一个继承层次结构中,由它来为派生类提供一个公共的根,派生类将具体实现在其基类中作为接口的操......

魏波 3565

C++惯用法之空基类优化

C++ 中每个对象的实例都可以通过取地址运算符获取其在内存布局中的开始位置,因此每个类对象至少需要占用一个字节的空间。空类是指不包含非静态数据成员的类,但是可以包含及静态成员。C++ 中空类的大小是 1 字节。结果是1,因为空类同样可以被实例化,每个实例在内存中都有一个独一无二的地址,为了达到这个目的,编译器往往会给一个空类隐含的加一个字节,这样空类在实例化后在内存得到了独一无二的地址.所以上述大小为1。

红军不怕远征难,万水千山只等闲 1707

【C++高级主题】转换与多个基类

在 C++ 的面向对象编程中,多重继承允许一个类同时继承多个基类的特性,这在实现复杂接口(如 “可绘制”+“可交互” 组件)或复用多组独立功能时非常有用。但随之而来的挑战是:当派生类对象被转换为不同基类的指针或引用时,如何确保虚函数调用的正确性?多个基类的虚析构函数如何协同工作?

byte轻骑兵的技术小窝 1236

C/C++编程:空基类优化

C++类常为”空“,这就意味着在运行期其内部表示不耗费任何内存。这常见于只包含类型成员,非虚成员函数和静态数据成员的类,而非静态数据成员、虚函数和虚基类会在运行期耗费内存 即使是空类,其大小也不会为0 #include <iostream> class EmptyClass{ }; class EmptyClass1{ static int i; }; int EmptyClass1::i = 1; class EmptyClass2{ static int i;

OceanStar的博客 1802

C++继承(派生类的定义方式、派生类的隐藏、菱形继承、虚基表、基类成员地址)

继承是面向对象程序设计的一个重要机制,通过继承,可以利用已有的数据类型来定义新的数据类型,实现代码复用。继承允许**在保持原有类特性的基础上进行扩展**,增加功能。 已存在的用来派生新类的类称为基类(或父类),由父类派生出的类称为派生类(或子类)。派生继承基类的成员,但派生类对基类成员的访问受继承方式和基类成员所处于的作用域限定符限制。

laimaxgg 1375

详解C++中基类与派生类的转换以及虚基类

C++基类与派生类的转换 在公用继承、私有继承和保护继承中,只有公用继承能较好地保留基类的特征,它保留了除构造函数和析构函数以外的基类所有成员,基类的公用或保护成员的访问权限在派生类中全部都按原样保留下来了,在派生类外可以调用基类的公用成员函数访问基类的私有成员。因此,公用派生类具有基类的全部功能,所有基类能够实现的功能, 公用派生类都能实现。而非公用派生类(私有或保护派生类)不能实现基类的全部

tkp2014的专栏 3412

C++虚基类

C++虚基类介绍

m0_52525841的博客 1304

C++基类与派生类类型转换以及虚基类

参考: https://www.jb51.net/article/72586.htm# .C++基类与派生类的转换 在公用继承、私有继承和保护继承中,只有公用继承能较好地保留基类的特征,它保留了除构造函数和析构函数以外的基类所有成员,基类的公用或保护成员的访问权限在派生类中全部都按原样保留下来了,在派生类外可以调用基类的公用成员函数访问基类的私有成员。因此,公用派生类具有基类的全部功能,所有基类能够实现的功能, 公用派生类都能实现。而非公用派生类(私有或保护派生类)不能实现基类的全部功能(例如在派生类外不能

Vergesson 697

【C++】关键字:virtual 虚函数 虚基类

virtual在英文中表示“虚”、“虚拟”的含义。c++中的关键字“virtual”主要用在两个方面:虚函数与虚基类。下面将分别从这两个方面对virtual进行介绍。

Friday 2371

C++学习笔记-基类、派生类与虚函数关系

基类(Base Class)是面向对象编程中继承的起点,它定义了派生类将继承的属性和行为。基类可以包含数据成员和成员函数,这些数据成员和成员函数可以被派生类继承和使用。基类的主要作用是为派生类提供一个共同的接口和一组基本的实现,使得派生类可以共享基类的代码和数据结构。派生类(Derived Class)是从一个或多个基类继承而来的类。在C++中,派生类通过继承机制获得基类的成员(包括数据成员和成员函数),并且可以在此基础上添加新的成员或修改继承而来的成员。

chen_mp的博客 2659

c++之虚函数和基类指针

  1.基类指针虽然获取派生类对象地址,却只能访问派生类从基类继承的成员 1 #include <iostream> 2 using namespace std; 3 4 //通过基类指针只能访问从基类继承的成员 5 class A 6 { 7 public: 8 A(char x) 9 { 10 ...

atr82275的博客 494
上一篇: ActivityRecordInputSink深入剖析全网独家分析
下一篇: SurfaceFlinger实战dump获取单个Layer图像方案学员改进成果
千里马学框架
博客等级 码龄6年 1万+粉丝 650原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值