背景
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.csdn.net/effort_study/article/details/119488496
本文章更多详细代码和资料需要购买课程获取
七件套专题:
点击这里
https://mp.weixin.qq.com/s/Qv8zjgQ0CkalKmvi8tMGaw
hal+perfetto+surfaceflinger
https://mp.weixin.qq.com/s/LbVLnu1udqExHVKxd74ILg
私聊作者+v(androidframework007)
视频试看:
https://www.bilibili.com/video/BV1wc41117L4/