多继承的this指针问题,帮忙解释一下结果

xgbing
博客专家认证
2008-11-15 02:36:35
#include <stdlib.h>
#include <stdio.h>



class CBase1
{
public:
CBase1(){a1 = 1;}
virtual void fun1()
{

};

int a1;
};


class CBase2
{
public:
CBase2(){a2 = 2;}

void setvalue()
{
clsAddr = this;
}

virtual void fun2() = 0;
int a2;

static void * clsAddr;
};

void * CBase2::clsAddr = 0;


class CDrive1: public CBase1, public CBase2
{
public:
void fun2()
{
setvalue();
};

static void print()
{
CDrive1 *self = (CDrive1 *)clsAddr;

printf("a1 = %d\n", self->a1);
}

};


int main()
{
CDrive1 t;

t.fun2();

t.print();
system("pause");
}

...全文
285 25 打赏 收藏 转发到动态 举报
写回复
用AI写文章
25 条回复
切换为时间正序
请发表友善的回复…
发表回复
cba_v 2008-11-17
  • 打赏
  • 举报
回复
up
winingsky 2008-11-16
  • 打赏
  • 举报
回复
up,学习!
wzyzb 2008-11-16
  • 打赏
  • 举报
回复
up
backway 2008-11-16
  • 打赏
  • 举报
回复
up!
backway 2008-11-16
  • 打赏
  • 举报
回复
up!
编程-鸟人-_-- 2008-11-16
  • 打赏
  • 举报
回复
Up!
K行天下 2008-11-15
  • 打赏
  • 举报
回复
up
GP625 2008-11-15
  • 打赏
  • 举报
回复
mark
gccdy 2008-11-15
  • 打赏
  • 举报
回复
make
太乙 2008-11-15
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 zmlovelx 的回复:]
引用 14 楼 hqin6 的回复:
C/C++ code刚打球去了,累死了,呵呵,没能及时回答,还请见谅啊~~~

我下午也去打球了. 现在才回来 你打的也太快了吧.

这个问题可以看看 深度探索c++对象模型
[/Quote]

身高,体重,场上位置!
帅得不敢出门 2008-11-15
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 hqin6 的回复:]
C/C++ code刚打球去了,累死了,呵呵,没能及时回答,还请见谅啊~~~
[/Quote]
我下午也去打球了. 现在才回来 你打的也太快了吧.

这个问题可以看看 深度探索c++对象模型
太乙 2008-11-15
  • 打赏
  • 举报
回复
刚打球去了,累死了,呵呵,没能及时回答,还请见谅啊~~~
太乙 2008-11-15
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 xgbing 的回复:]
引用 5 楼 hqin6 的回复:
C/C++ code

实际:
+------------------+
| CB1 |
+------------------+
| CB1::a1(1) | 转换后:
+------------------+ +---------------
| CB2 | | CB1
+------------------+ +-------------------
| CB2::a2(2) | | CB1::a1(从左边读过来,是2)
+------------------+ +------------------

去掉CBase1::fun1的virtual后,照上面…
[/Quote]



很碰巧!

实际:

+------------------+
| CB1 |
+------------------+
| CB1::a1(1) | 转换后:
+------------------+ +---------------
| CB2 | | CB1
+------------------+ +-------------------
| CB2::a2(2) | | CB1::a1(从左边读过来,是2)
+------------------+ +------------------


上面这个只是我的一个示例,省略了虚函数所占的字节,实际上:

我重新来解释一下:



首先,setvalue里的this指向的肯定是cb2:vb吧??

这点毫无疑问!

那么对于第一种情况(未去掉CB1::vb)

那么和我上面描述的无差别!

+------------------+
| CB1::vb |
+------------------+
| CB1::a1(1) | 转换后:
+------------------+ +---------------
| CB2::vb | | CB1::vb
+------------------+ +-------------------
| CB2::a2(2) | | CB1::a1(从左边读过来,是2)
+------------------+ +------------------
| CB2::vb
+------------------
| CB2::a2(这里就是未定义的,lz可以试试,不输出a1,输出a2试试,我试了,输出的是a2 = 4334185
+------------------



那么如果把CB2的virtual去掉呢?

情况有变:

现在的内存变为:




转换前: 转换后:
+------------------+ +---------------
| CB2::vb | | CB2::vb
+------------------+ +-------------------
| CB2::a2(2) | | CB2::a2(从左边读过来,是2)
+------------------+ +------------------
| CB1::a1(1) | | CB1::a1(1),此时lz可以输出a1,a2,试试,都对!


因为CB1没有vb,那么我们知道,如果有virtual,就有vb表,那么this指向这个表地址

所以内存的布局变了,变成上面的这样了,开始的不再是CB1,而是CB2


不知道我说明白没?


xiaopoy 2008-11-15
  • 打赏
  • 举报
回复
帮顶。

建议LZ下载个调试器自己看看实际情况。
liumingrong 2008-11-15
  • 打赏
  • 举报
回复
一般来说会按照派生声明次序构造基类对象,但是有虚函数的例外
此时第一个父类没有虚函数,对象也就没有虚函数指针,但是第二个基类有虚函数,
编译器优化的话,派生类对象的内存布局会先构造有虚函数的对象,
也就是会将CBase2放在“前面”,这样的话你正好碰巧能得到期望的结果。
[Quote=引用 7 楼 xgbing 的回复:]
你们说的很明白,但为什么我去了CBase1中的virtual就正确了。按上面的说法,CBase1内存区域只是去了个虚函数表。
class CBase1
{
public:
CBase1(){a1 = 1;}
void fun1() //把virtual去了
{

};

int a1;
};
[/Quote]
jia_xiaoxin 2008-11-15
  • 打赏
  • 举报
回复
CDrive1 t; 当生成t对象时,生成的对象内存空间中包含父类,CBase2 ,CBase1的实例化部分,以及自身CDrive1 的实例化部分。
fun2是虚函数,所以t.fun2(); 中this指针是CDrive1,而setvalue不是虚函数,所以调用setvalue时,此时this指针是CBase2
也就是说clsAddr此时指向的是CBase2,
CDrive1 *self = (CDrive1 *)clsAddr; 这一句将派生类指针指向了基类,在向下类型转化中将丢失部分信息,此时本来要指向a1
的部分丢失,而指向了a2的内存空间,所以输出的是a2的值,而本来要指向a2的部分将指向了未知。

如果是class CDrive1: public CBase2, public CBase1
这样继承的,那么输出的将是a1 = 1,
而a2为2.

xgbing 2008-11-15
  • 打赏
  • 举报
回复
去掉CBase1::fun1的virtual后,照理说CBase1内存区域只是少了个虚函数表,为啥为啥
xgbing 2008-11-15
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 hqin6 的回复:]
C/C++ code

实际:
+------------------+
| CB1 |
+------------------+
| CB1::a1(1) | 转换后:
+------------------+ +---------------
| CB2 | | CB1
+------------------+ +-------------------
| CB2::a2(2) | | CB1::a1(从左边读过来,是2)
+------------------+ +------------------
[/Quote]
去掉CBase1::fun1的virtual后,照上面的说法,也应是:
+------------------+
| CB1 |
+------------------+
| CB1::a1(1) | 转换后:
+------------------+ +---------------
| CB2 | | CB1
+------------------+ +-------------------
| CB2::a2(2) | | CB1::a1(从左边读过来,是2)
+------------------+ +------------------

可去掉virtual后结果a1 = 1结果是正确的????
xgbing 2008-11-15
  • 打赏
  • 举报
回复
你们说的很明白,但为什么我去了CBase1中的virtual就正确了。按上面的说法,CBase1内存区域只是去了个虚函数表。
class CBase1
{
public:
CBase1(){a1 = 1;}
void fun1() //把virtual去了
{

};

int a1;
};
lxj1234567 2008-11-15
  • 打赏
  • 举报
回复
来学习。
加载更多回复(5)

64,282

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧