C++ 多重继承,c++指针类型转换
在C中,指针的类型转换经常发生,比如将派生类指针转换为基类指针,将基类指针转换为派生类指针。指针的本质其实是一个整数,用来记录进程的虚拟内存空间中的地址号,指针的类型决定了编译器对它所指向的内存空间的解释。
基于以上理解,似乎可以得出一个结论,C中指针的类型转换不会改变指针的值,而只是改变指针的类型(即改变编译器对指向内存的指针的解释),但这个结论在C多重继承下并不成立。
请看下面的代码:
1 #包括iostream
2使用命名空间std
4级CBaseA
6公共:
7 char m _ A[32];
8 };
10类CBaseB
12公共:
13 char m _ B[64];
14 };
16类CDerive : public CBaseA,public CBaseB
18公共:
19 char m _ D[128];
20 };
23 int main()
25 auto pD=new CDerive
26 auto pA=(CBA sea *)pD;
27 auto pB=(CBA SEB *)pD;
29 cout pA \ n pB \ n pD endl
30 cout(pD==pB)endl;
31 }
这段代码的输出是:
0x9f1080
0x9f10a0
0x9f1080
一个
可以看出,在类型转换后,指向同一堆上新的内存指针的值会发生变化。原因是来自c中多重继承的内存布局。
新CDerive执行后,生成的内存布局如下:
同时我们注意到pB和pD的指针差正好是CBaseA占用的32字节内存,而pA和pD都指向同一个地址。这是因为当派生类的指针转换为基类的指针时,编译器会将指针的值移动到对象内存中基类的起始位置。
但是为什么C要这样设计呢?
想象一下,按照上面的场景,如果pB和pA都指向对象的第一个地址,那么在使用pB指针定位CBaseB的成员变量m_B时,编译器要将pB指针偏移32个字节,从而跳过CBaseA的内存部分。而如果pB指针是这样生成的,autopb=newcbaseb那么用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 c derivative生成的内存对象),所以编译器在这里又插了一脚,这样我们就可以享受==运算的上层语义了。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。