快乐虾
http://blog.csdn.net/lights_joy/
本文适用于
Xp sp3
Vs2008
欢迎转载,但请保留作者信息
这次我们添加一个子类,父类和子类均不带虚函数:
class CParent
{
public:
int parent_a;
int parent_b;
public:
void parent_f1()
{
parent_a = 0x10;
}
void parent_f2()
{
parent_b = 0x20;
}
};
class CChild : public CParent
{
public:
int child_a;
int child_b;
public:
void child_f1()
{
child_a = 0x30;
}
void child_f2()
{
child_b = 0x40;
}
};
先给这些成员变量赋几个值:
child.parent_a = 1;
0041138E C7 05 50 71 41 00 01 00 00 00 mov dword ptr [child (417150h)],1
child.parent_b = 2;
00411398 C7 05 54 71 41 00 02 00 00 00 mov dword ptr [child+4 (417154h)],2
child.child_a = 3;
004113A2 C7 05 58 71 41 00 03 00 00 00 mov dword ptr [child+8 (417158h)],3
child.child_b = 4;
004113AC C7 05 5C 71 41 00 04 00 00 00 mov dword ptr [child+0Ch (41715Ch)],4
观察&child所指的内存区内容:
0x00417150 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 ................
很明显,VS将父类和子类的数据成员合并到同一块内存区域,但是同样没有往里面加额外的东西,&child指针将指向第一个成员parent_a。
观察函数调用:
child.parent_f1();
00411840 B9 50 71 41 00 mov ecx,offset child (417150h)
00411845 E8 78 F9 FF FF call CParent::parent_f1 (4111C2h)
child.child_f1();
0041184A B9 50 71 41 00 mov ecx,offset child (417150h)
0041184F E8 64 F9 FF FF call CChild::child_f1 (4111B8h)
和简单父类的函数调用没什么两样。用ECX传递this指针。
在子类里添加两个和父类同名的成员变量:
class CChild : public CParent
{
public:
int child_a;
int child_b;
int parent_a;
int parent_b;
………
再执行前面的赋值语句:
child.parent_a = 1;
0041180E C7 05 04 75 41 00 01 00 00 00 mov dword ptr [child+10h (417504h)],1
child.parent_b = 2;
00411818 C7 05 08 75 41 00 02 00 00 00 mov dword ptr [child+14h (417508h)],2
child.child_a = 3;
00411822 C7 05 FC 74 41 00 03 00 00 00 mov dword ptr [child+8 (4174FCh)],3
child.child_b = 4;
0041182C C7 05 00 75 41 00 04 00 00 00 mov dword ptr [child+0Ch (417500h)],4
可以发现赋值时使用的偏移量发生了变化,观察&child所在的内存区:
0x004174F4 00 00 00 00 00 00 00 00 03 00 00 00 04 00 00 00 ................
0x00417504 01 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00 ................
可以看到合并后的内存有6个整数,且对child.parent_a的赋值其实是对子类的成员进行赋值。
而当我们用下面的赋值语句时:
pparent = &child;
00412E44 C7 05 E4 74 41 00 F4 74 41 00 mov dword ptr [pparent (4174E4h)],offset child (4174F4h)
pparent->parent_a = 1;
00412E4E A1 E4 74 41 00 mov eax,dword ptr [pparent (4174E4h)]
00412E53 C7 00 01 00 00 00 mov dword ptr [eax],1
pparent->parent_b = 2;
00412E59 A1 E4 74 41 00 mov eax,dword ptr [pparent (4174E4h)]
00412E5E C7 40 04 02 00 00 00 mov dword ptr [eax+4],2
从偏移量就可以看出它是对父类的成员进行赋值。
在子类里面添加一个和父类同名的函数,再进行函数调用:
pchild = &child;
00412E26 C7 05 F0 74 41 00 F4 74 41 00 mov dword ptr [pchild (4174F0h)],offset child (4174F4h)
pchild->parent_f1();
00412E30 8B 0D F0 74 41 00 mov ecx,dword ptr [pchild (4174F0h)]
00412E36 E8 9B E3 FF FF call CChild::parent_f1 (4111D6h)
pparent = &child;
00412E3B C7 05 E4 74 41 00 F4 74 41 00 mov dword ptr [pparent (4174E4h)],offset child (4174F4h)
pparent->parent_f1();
00412E45 8B 0D E4 74 41 00 mov ecx,dword ptr [pparent (4174E4h)]
00412E4B E8 72 E3 FF FF call CParent::parent_f1 (4111C2h)
从反汇编的结果可以明显看出使用父类指针和使用子类指针调用同名函数时的差异。
vs2008下C++对象内存布局(1)(2009-9-9)