|
|
我们天天在喊着面向对象,究竟我们对对象了解多少?我基于对对象进行一些更深的了解的目的,做了下面的研究。
请看下面的体系:
class A
{
public:
virtual void test()
{
cout<<"ttt"<<endl;
}
virtual void mytens(){}
int a;
};
class C
{
public:
virtual void test1(){}
int c;
};
class B : public A ,public C
{
public:
virtual void test2()
{
cout<<"aaa"<<endl;
}
int b;
};
其中,sizeof(A),sizeof(C)是8字节,sizeof(B)是20字节。为什么会这样那?让我们先看看A和C里分别有些什么。
首先肯定会有一个int,另外多出来的4字节是什么?仔细看,class是有虚函数的,于是可以大胆猜测,那4个字节是虚函数表指针。事实上也是如此。我语文不好。就直接把这个类里的数据在内存里的分布写出了。不玩虚的了。
Vtable 4字节
Int 4 字节
在我的vs.net2003里vtable是在所有的数据之前的。不同的编译器可能会不一样。但是就我个人意见,最好还是放到所有数据之前,这样this指针的位置其实就是虚函数表的位置。可能会带来一些性能的优化。
现在再看B中数据在内存里的映象:
Class A //对象A的数据 8字节
Class C //对象C的数据 8字节
Int //4字节
这么分布不难理解。对象在内存里的顺序就是定义他们的顺序,继承的时候也是从左向右排列父类。关键在于,B的虚函数表在哪里?查看A虚函数表中的数据,可以知道,B的虚函数表其实是和A共享了。也就是说,B的虚函数是直接作为项添加到A的虚函数表里,至于为什么选择A。其实还是刚才所说的,这样this指针的位置其实就是虚函数表的位置。可能会带来一些性能的优化。你可以用如下的汇编代码来调用虚函数们:
Temp是一个B对象的指针
mov eax,temp
mov edx,[eax]
push edx
call [edx]
pop edx
add edx,4
push edx
call [edx]
pop edx
add edx,4
call [edx]
那么就不难理解多态了。实现多态其实就是修改虚函数表里的项。具体情况请大家自己动手看。
下面再看指针转换。当你把一个B指针转换为A指针的时候,可以看到其数值并没有变化。这个不难理解。你看B内部数据的内存映象,第一项数据其实不就是A么?那么我们可以大胆猜测,如果转化为C指针的话,那么指针的指就会调整到C的位置上,也就是ptr+=sizeof(A)。写代码验证看看,果然。
OK。我要写的就是以上这些。可以看到,我其实语文很差,同志们还要自己多多理解。如果有什么不足或者错误之类的。可以跟我联系。老规矩,放上联系方式:
秋樱工作室:http://www.autsak.com
我的Email: sakura@china.com
MSN: autsak@hotmail.com (本邮箱不收信) |
|