首页
社区
课程
招聘
[脚印]2011年25周(6.24) C++内存结构
2011-6-23 21:36 10058

[脚印]2011年25周(6.24) C++内存结构

2011-6-23 21:36
10058
声明: 内容都是书上的,自己重写下,加深下印象,如有不妥请指出。
参数书籍信息:
<<高质量C/C++>> 第三版 第12章C++面向对象程序设计 电子工业出版社
<<深度探索C++对象模型>> 第1章关于对象 华中科技大学出版社

先看下简单类的代码和数据放置的位置
int CAnimal::m_snType = 0x12345678;

int _tmain(int argc, _TCHAR* argv[])
{    
    CAnimal AnimalObj;
    CAnimal *lpObj = &AnimalObj;
    printf("%d,%s", lpObj->m_snType, lpObj->m_szName);

    return 0;
}


函数位置,构造函数和析构函数都在代码区
class CAnimal
{
public:
    CAnimal()
    { 
        strncpy(m_szName, "Test!", sizeof(m_szName));
01322453  mov         esi,esp 
01322455  push        0Ah  
01322457  push        offset string "Test!" (13279B0h) 
0132245C  mov         eax,dword ptr [this] 
0132245F  push        eax  
01322460  call        dword ptr [__imp__strncpy (132B3B4h)] }
     ~CAnimal()
    {
        _asm NOP 
00AD210C  nop              
    printf("%d,%s", lpObj->m_snType, lpObj->m_szName);
013248E6  mov         esi,esp 
013248E8  mov         eax,dword ptr [ebp-20h]   //指针保存的就是类的首址(这里也就字符串的地址)
013248EB  push        eax  
013248EC  mov         ecx,dword ptr [CAnimal::m_snType (132A00Ch)] //(常量区)至少不再栈中
013248F2  push        ecx  
013248F3  push        offset string "%d,%s" (132783Ch) 
013248F8  call        dword ptr [__imp__printf (132B3ACh)]
类的内存布局如下所示,内存中之存在非静态成员m_smName (图一)

这里Class CAnimal里面其实只有一个成员就是 m_szName

在类中增加析构/虚函数和静态函数,将m_szName改为16byte
    virtual ~CAnimal()
    virtual bool isCanSay(){}
    static bool isCanFly(){}
main函数中,这次不用指针在保存对象
    CAnimal AnimalObj;
    AnimalObj.isCanSay();
    AnimalObj.isCanFly();
    printf("class大小:%d ,%d,%s", sizeof(AnimalObj), AnimalObj.m_snType, AnimalObj.m_szName);

看下汇编代码
    CAnimal AnimalObj;
000348F0  lea         ecx,[ebp-28h] 	//所谓的this,就是class内存块的首地址
000348F3  call        CAnimal::CAnimal (310D7h) 
000348F8  mov         dword ptr [ebp-4],0 
    AnimalObj.isCanSay();
000348FF  lea         ecx,[ebp-28h] 
00034902  call        CAnimal::isCanSay (312A3h) 
    AnimalObj.isCanFly();
00034907  call        CAnimal::isCanFly (312ADh) 
    printf("class大小:%d ,%d,%s", sizeof(AnimalObj), AnimalObj.m_snType, AnimalObj.m_szName);
0003490C  mov         esi,esp 
0003490E  lea         eax,[ebp-24h] 
00034911  push        eax  
00034912  mov         ecx,dword ptr [CAnimal::m_snType (3A00Ch)] 
00034918  push        ecx  
00034919  push        14h  
0003491B  push        offset string "class\xb4\xf3\xd0\xa1\xa3\xba%d ,%d,%s" (37C08h) 
00034920  call        dword ptr [__imp__printf (3B3ACh)]

    virtual ~CAnimal()
{
    _asm NOP 
0003210C  nop  
  (图二)


0312a3  jmp         CAnimal::isCanSay (312xxh)
02129e  jmp      CAnimal::~CAnimal (000321xx)

有单继承的情况
class CCat : public CAnimal
{
public:
    CCat(){m_nTest = 0;}
    virtual bool isCanSay(){return true;}
    virtual bool isEatFish(){return true;}
    int  m_nTest;
};
    CCat  CatObj;
00D14930  lea         ecx,[ebp-48h] 
00D14933  call        CCat::CCat (0D112CBh) 
	    CCat(){m_nTest = 0;}
00D12390  push        ebp  
00D14938  mov         byte ptr [ebp-4],1 
    CatObj.isCanSay();
00D1493C  lea         ecx,[ebp-48h] 
00D1493F  call        CCat::isCanSay (0D112B2h) 
00D112B2  jmp         CCat::isCanSay (0D11A20h) //虚表的下标1位置
    CatObj.isCanFly();
00D14944  call        CAnimal::isCanFly (0D112ADh) 
00D112AD  jmp         CAnimal::isCanFly (0D11930h)
    printf("class大小:%d ,%d,%s", sizeof(CatObj), CatObj.m_snType, CatObj.m_szName);
00D14949  lea         eax,[ebp-44h] 
00D1494C  mov         esi,esp 
00D1494E  push        eax  
00D1494F  mov         ecx,dword ptr [CAnimal::m_snType (0D1A00Ch)] 
00D14955  push        ecx  
00D14956  push        18h  
00D14958  push        offset string "class\xb4\xf3\xd0\xa1\xa3\xba%d ,%d,%s" (0D17C08h) 
(图三)

CCat类内内存的变化是增加了一个int变量,只是是0,看不出来,输出大小为24(4(虚表)+16+4(int))
虚表的个数增加了一个,就是新的虚函数isEatFish, isCanSay被CCat新增的虚函数替换了,

再看下复杂点的
class CAnimal
{
public:
    CAnimal()
    { 
        strncpy(m_szName, "Test!", sizeof(m_szName));
    }
    virtual ~CAnimal()
    {
        _asm NOP 
    }
    virtual bool isCanSay(){return false;}
    static bool isCanFly(){return false;}

public:
    char m_szName[16];
    static int m_snType;
};

int CAnimal::m_snType = 0x12345678;

class CCat : virtual public CAnimal
{
public:
    CCat(){m_nCatTest = 0x123;}
    //virtual bool isCanSay(){return true;}
    virtual bool isEatFish(){return true;}
    int  m_nCatTest;
};

class CCDog: virtual public CAnimal
{
public:
    CCDog(){m_nDogTest = 0x789;}
    virtual ~CCDog(){}
    virtual bool isEatMeat(){return true;}
    //virtual  bool isCanSay(){return true;}
    int m_nDogTest;
};

class CPet :  public  CCat,  public  CCDog
{
public:
    virtual bool isCanDomestication(){return true;} 
};


int _tmain(int argc, _TCHAR* argv[])
{    
    CPet CpetObj;
    CpetObj.isEatFish();
    CpetObj.isEatMeat();
    CpetObj.isCanSay();

    return 0;
}

看下汇编
   CPet CpetObj;
012F24B1  push        1    
012F24B3  lea         ecx,[ebp-84h] 
012F24B9  call        CPet::CPet (12F1203h) 
012F24BE  mov         byte ptr [ebp-4],2 
    CpetObj.isEatFish();
012F24C2  lea         ecx,[ebp-84h] 
012F24C8  call        CCat::isEatFish (12F117Ch) 
    CpetObj.isEatMeat();
012F24CD  lea         ecx,[ebp-78h] 
012F24D0  call        CCDog::isEatMeat (12F1131h) 
    CpetObj.isCanSay();
012F24D5  mov         eax,dword ptr [ebp-80h] 
012F24D8  mov         ecx,dword ptr [eax+4] 
012F24DB  lea         ecx,[ebp+ecx-80h] 
012F24DF  call        CAnimal::isCanSay (12F11C2h)
(图四)
[ATTACH]58291[/ATTACH] 
虚表对应的跳转代码
[code]
0x12f89a4
	012F117C  jmp         CCat::isEatFish (12F2880h) 
012F110E  jmp         CPet::isCanDomestication (12F2D60h) 
0x12f8998
012F1131  jmp         CCDog::isEatMeat (12F29E0h) 
0x12f8988
012F123A  jmp         CPet::`scalar deleting destructor' (12F2E00h) 
012F11C2  jmp         CAnimal::isCanSay (12F26E0h) 

整理一下,对应图中红色部分,目前还不是很清楚为啥子,等得闲时再看看 (图五)


总结下:
    C++内存分布状况非静态成员都在类内,静态成员在常量区,非virtual函数在在class不扯关系(不保存表关系),虚函数class内会有虚表指针指向虚表,虚表中保存虚函数的地址,在调用的时候通过间接取调用(要用new才能看到到)。
    有同名同参的虚函数,继承改写,则派生类的虚表中base class的虚表会被覆盖,多继承就多几个虚表,成员对象规则符合一般规则。
   菱形的复杂结构,等搞清楚。。。。

                                                                                           五边形 (2011年6月24日)

[培训]《安卓高级研修班(网课)》月薪三万计划

上传的附件:
收藏
点赞5
打赏
分享
最新回复 (16)
雪    币: 185
活跃值: (130)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
五边形 1 2011-6-23 21:37
2
0
我继承下,改写之
雪    币: 6592
活跃值: (685)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
willapple 2011-6-23 23:14
3
0
学习下!
雪    币: 165
活跃值: (1508)
能力值: ( LV9,RANK:250 )
在线值:
发帖
回帖
粉丝
Nisy 5 2011-6-24 17:52
4
0
C++ 的类机制是在逻辑上封装 编译上独立
雪    币: 185
活跃值: (130)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
五边形 1 2011-6-24 23:33
5
0
感谢关注,不过说的比抽象类还抽象,青蛙跳水啊
雪    币: 415
活跃值: (34)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
笨奔 1 2011-6-25 13:47
6
0
不懂这些,太乱啦。
雪    币: 435
活跃值: (110)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
tornodo 1 2011-6-25 22:53
7
0
提供pdf就好了
雪    币: 20
活跃值: (84)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
tihty 2 2011-6-26 05:17
8
0
声明: 内容都是书上的,自己重写下,加深下印象

lz看的是哪本书?
雪    币: 213
活跃值: (144)
能力值: ( LV10,RANK:160 )
在线值:
发帖
回帖
粉丝
zouzhiyong 3 2011-6-26 11:38
9
0
mark~~~,对于C++的逆向比较有意思~~~
雪    币: 220
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
广海混沌 2011-6-26 11:43
10
0
思路是很不错的 支持下
雪    币: 185
活跃值: (130)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
五边形 1 2011-6-26 13:09
11
0
书籍为:
<<高质量C/C++>> 第三版 第12章C++面向对象程序设计 电子工业出版社
<<深度探索C++对象模型>> 第1章关于对象 华中科技大学出版社
发现对象模型的第三章好像也讲Data的,计划下个周再看3章,估计有东西要更新,这里占个坑先,文档到时也会附上。也希望过来人能多指点一二。
雪    币: 64
活跃值: (157)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
liuqiangni 2 2011-6-26 13:24
12
0
刚好昨天晚上翻了下C++ 的虚拟继承和多重继承,今天就再次看到了...巧啊!~~
雪    币: 397
活跃值: (292)
能力值: ( LV9,RANK:410 )
在线值:
发帖
回帖
粉丝
neineit 10 2011-6-27 10:03
13
0
顶一下,记得effective c++ 还有这个很类似的例子。
雪    币: 7923
活跃值: (2201)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
speedboy 2011-6-28 14:51
14
0
NISY 是术业有专攻
雪    币: 651
活跃值: (448)
能力值: ( LV12,RANK:360 )
在线值:
发帖
回帖
粉丝
Mx¢Xgt 7 2011-6-28 17:36
15
0
图文并茂,不错,顶!!
雪    币: 322
活跃值: (113)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
高军 2011-6-29 17:53
16
0
支持共享!!!
雪    币: 160
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xianzq 2011-7-1 22:25
17
0
深入浅出MFC第三章!
游客
登录 | 注册 方可回帖
返回