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

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

以下程序例子:

  1. #include <iostream>   
  2. using namespace std;   
  3.   
  4. class ca{   
  5.         char m_a[32];   
  6. };   
  7. class cb{   
  8.         char m_b[64];   
  9. };   
  10. class cd : public ca,public cb{   
  11.         char m_d[128];   
  12. };   
  13. int main(int argc,char **argv)   
  14. {   
  15.         cd *pD = new cd;   
  16.         ca *pA = (ca *)pD;   
  17.         cb *pB = (cb *)pD;   
  18.   
  19.         cout << pA << endl;   
  20.         cout << pB << endl;   
  21.         cout << pD << endl;   
  22.   
  23.         cout << (pD == pB) << endl;   
  24.   
  25.         return 0;   
  26. }  

这段代码的输出结果是:

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

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

此时,pA 与 pD都指向ca对象的起始地址,pB 指向其起始地址刚好与ca对象的起始地址差32,所以可以看到pB打印出的地址比pA和pD的地址差32,而pA与pD均指向首地址。

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

 

C++在多重继承下的指针类型强制类型转换的一些问题

发表评论

电子邮件地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.