第一次写自己的c++学习心得,欢迎大家拍砖

smilewang 2003-07-03 11:56:14
在多继承中,基类指针是如何指向派生类对象的?
各位看官看到这个题目可能要笑了,这么简单清楚的事情也要罗嗦,其实,简单的事情仔细想想,有时也能想出问题来.
好了,闲话少叙,先说一段关于多继承的程序.
#include <iostream>
#include <conio.h>
using namespace std;
//
class Base{
public:
int _i1;
int _i2;
int _i3;
virtual void displayA()
{
cout<<"in base,display function."<<endl; }
};
//
class AnotherBase{
public:
int _k;
virtual void displayB()
{
cout<<"in anotherbase,displayB function."<<endl;
}
};
//
class Derive:public Base,public AnotherBase{
public:
int _n;
void displayA() {cout<<"derive ,displayA."<<endl;}
void displayB() {cout<<"derive ,displayB."<<endl;}
};

int main()
{
Derive myDerive,*pDerive=&myDerive;
Base *pBase=NULL;
AnotherBase *pAnotherBase=NULL;

pBase=pDerive; // <--- attention
pAnotherBase=pDerive; // <--- attention

cout<<"the address stored in pBase="<<pBase<<endl;
cout<<"the address stored in pAnotherBase="<<pAnotherBase<<endl;
//cout<<"size of class Base is "<<sizeof(Base)<<endl;
//cout<<"size of class AnotherBase is "<<sizeof(AnotherBase)<<endl;
//cout<<"size of class Derive is "<<sizeof(Derive)<<endl;
getchar();
return 0;
}

每个人的运行结果都不会一样。我这里的结果是

the address stored in pBase=0012FF64
the address stored in pAnotherBase=0012FF74

是不是有一些惊讶?同一个pDerive分别赋值给pBase,pAnotherBase指针,居然产生了两个不同的值。让我们再仔细的看一下:pAnotherBase和pBase的差值为16个字节,而这16个字节恰好为一个Base类对象的大小!口说无凭,将程序最后几行中的注释去掉后再运行,就可以看到结果。

size of class Base is 16
size of class AnotherBase is 8
size of class Derive is 28

在我们做出最后的解答前,先提出两个问题:
1 基类的对象在内存中是如何存储的?
2 派生类对象在内存中是如何存储的?
我们先来看看问题1:
任何成员函数都不占据存储空间,所以对于基类对象来说,只有非静态的成员变量才占据内存空间。对于我们的Base类来说,其对象的大小为sizeof(int)*3=12,
还有4个字节呢?这4个字节就是vptr.当然,如果类中没有虚函数,也就没有vptr。 这个问题,在<<深入浅出MFC>>64-68页有过论述。

解决了第一个问题,第二个问题也好办了,派生类对象是先存储了基类子对象后,再存储派生类自己特有的部分。可是又有一个问题,在多继承中,派生类对象含有多个基类子对象,谁先?谁后?奥秘就在派生类的派生表里,哪个基类在先,哪个基类的子对象就先存储。(对于这个问题,你可以将Derive类派生表中Base和Another类的位置调换,再重新运行程序,你会发现pBase和pAnotherBase的差值变为-8,其绝对值正好是AnotherBase类对象的大小)

好,现在我们就将Derive类的对象在内存中的结构写出来。

内容 地址 字节大小
vptr(1) (Base类子对象) 0012FF64 4 字节
_i1 (Base类子对象) 0012FF68 4 字节
_i2 (Base类子对象) 0012FF6C 4 字节
_i3 (Base类子对象) 0012FF70 4 字节
vptr(2) (AnotherBase类子对象) 0012FF74 4 字节
_k (AnotherBase类子对象) 0012FF78 4 字节
_n (Derive类特有的部分) 0012FF7C 4 字节

Total 4*7=28=sizeof(Derive)
从这个结构中我们可以看出,为什么同一个pDerive分别赋值给pBase,pAnotherBase,这两个指针的值会不一样。为了在多继承中完成多态,编译器必须做一些手脚,使得pBase和pAnotherBase指向不同的地址。如果pAnother指向的不是vptr(2)处,而是vptr(1)处,呵呵,灾难将会发生。因为对于AnotherBase类来说
它不知道Base类的信息,所以它也无法解释从vptr(1)开始的内容。


得到的结论是:

在多继承中,将基类指针指向一个派生类的对象时,系统并不是简单的将对象的首地址赋值给基类指针。基类指针指向的地址为派生类中相应基类子对象的地址。而这个地址,未必就是派生类对象的首地址。
...全文
172 34 打赏 收藏 转发到动态 举报
写回复
用AI写文章
34 条回复
切换为时间正序
请发表友善的回复…
发表回复
MaiCle 2003-07-05
  • 打赏
  • 举报
回复
smilewang(急速传说):不好意思,是我看错了,再加上理解错了。汗啊。
willa 2003-07-05
  • 打赏
  • 举报
回复
WELL
leoli2003cn 2003-07-05
  • 打赏
  • 举报
回复
我也打算学c++
cxjddd 2003-07-04
  • 打赏
  • 举报
回复
加油。不错
何哀何欢 2003-07-04
  • 打赏
  • 举报
回复
赫赫,你真不应该看<<深入浅出MFC>>来学C++。否则自己得花很多时间来探索。
aiyinsitan 2003-07-04
  • 打赏
  • 举报
回复
ding
jjchzh 2003-07-04
  • 打赏
  • 举报
回复
怎么拍?砖在哪?
呵呵,谢了!
wowowowo 2003-07-04
  • 打赏
  • 举报
回复
ding
rexwell 2003-07-04
  • 打赏
  • 举报
回复
MI是很麻烦的
有很多人要求将它去掉
但是它也很重要,另外一些人的观点是这样的,它能在一些工程中起到很重要的作用
我对这个不好说
villager 2003-07-04
  • 打赏
  • 举报
回复
我拍
Kusk 2003-07-04
  • 打赏
  • 举报
回复
不错。看过《深度探索C++对象模型》吗?这本书专门讲这类底层机制的。
simouse 2003-07-04
  • 打赏
  • 举报
回复
slaker 2003-07-04
  • 打赏
  • 举报
回复
warrenchou 2003-07-04
  • 打赏
  • 举报
回复
xabba 2003-07-04
  • 打赏
  • 举报
回复
up
smilewang 2003-07-04
  • 打赏
  • 举报
回复
MaiCle(※不拉马的士兵※)
cout << *p1; 和cout << *p2; 得出的结果是一样的.

但是cout << p1; 和 cout << p2; 得出的结果还一样吗?
==================================================
答案:一样.

看下面的程序段.

int myInt=10;
int *p1=NULL,*p2=NULL;
p1=&myInt;
p2=p1;

cout<<myInt; //1
cout<<*p1; //2
cout<<*p2; //3

cout<<p1; //4
cout<<p2; //5

cout<<&p1; //6
cout<<&p2; //7
其中1\2\3相等 , 4\5相等, 6\7是两个不等的值.
worldnews 2003-07-04
  • 打赏
  • 举报
回复
收藏
MaiCle 2003-07-04
  • 打赏
  • 举报
回复
pBase=pDerive; // <--- attention
pAnotherBase=pDerive; // <--- attention

cout<<"the address stored in pBase="<<pBase<<endl;
cout<<"the address stored in pAnotherBase="<<pAnotherBase<<endl;


不正是我上面的:cout << p1; 和 cout << p2;吗?
MaiCle 2003-07-04
  • 打赏
  • 举报
回复
int *p1=NULL,*p2=NULL;
int myInt=10;
p1=&myInt;
p2=p1;//将p1所持有的地址的值复制给p2,也就是说p1和p2的值是一样的.指向同一个地址.


对*p1和*p2是一样,即:

cout << *p1; 和cout << *p2; 得出的结果是一样的.

但是cout << p1; 和 cout << p2; 得出的结果还一样吗?


sherlerliu 2003-07-04
  • 打赏
  • 举报
回复
顶!
加载更多回复(14)

64,637

社区成员

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

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