目录
类的定义
demo
#include <iostream>
using namespace std;
class Persion
{
public:
int m_age;
//void run(Persion *persion){
// //显示调用
// cout << persion->m_age << " run()" <<endl;
//}
void run(){
//this 存储函数调用者的地址,例如 this 存储 &persion 或 this 存储 &persion1
cout << this->m_age << " run()" <<endl;
}
};
void test(){
Persion persion; //persion对象占用4个字节:因为只有一个int类型(4个字节)的成员变量
persion.run(); //在编译过程中,将为函数分配一个内存地址,此次调用将编译成 call 函数地址。 如call 0086141A
Persion persion1; //persion1对象占用4个字节:因为只有一个int类型(4个字节)的成员变量
persion.m_age = 20;
persion.run(); //call函数地址 如call 0086141A
Persion *p = & persion; // 64位,p占用8个字节
p->m_age = 30;
p->run();
cout << "sizeof(persion) = " << sizeof(persion) <<endl;
cout << "sizeof(p) = " << sizeof(p) <<endl;
/*
persion对象和指针p的内存都在函数的栈空间,自动分配和回收
*/
}
int main(){
test();
return 0;
}
对象调用成员函数汇编解释
普通函数调用对应的汇编是call xxxxx地址
persion1.run();对应的汇编:
lea ecx,[ebp-0Ch] /取地址,其中 ebp-0Ch是persion1对象的地址,ecx存储者persion1的地址
call 00061366
下面是persion1.run()调用run()过程和生成的汇编:
void run(){
this->m_age = 3;
}
/*
mov dword ptr [ebp-8],ecx //persion1的对象的地址值放到了this指针所在的存储空间,其中ecx存放的是persion1的地址,ebp-8:this指针的地址
mov eax,dword ptr [ebp-8] //取出this指针里面存储的地址值放到eax,执行完后,eax里放的是persion1的地址值
mov dword ptr [eax],3 // 把3放到了persion1的存储空间
*/
内存空间
代码区 | 用于存放代码 | 上面代码块中run()内存在代码区 |
栈空间 | 1. 每调用一个函数就会给它分配一段连续的栈空间,等函数调用完毕后会自动回收这个栈空间 2.自动分配和释放 | persion, persion1 以及和对应的成员在栈空间 |
堆空间 | 需要主动申请和释放 | |
数据段(全局区) | 用于存放全局变量等 |
对象的内存的排布顺序
对象的内存的排布顺序按照成员变量定义的顺序
demo
/*
对象的内存的排布顺序按照成员变量定义的顺序
*/
#include <iostream>
using namespace std;
class Persion
{
public:
int m_id;
int m_age;
int m_height;
void display(){
cout << "id:" <<m_id << "age:" << m_age << "height:" << m_height<<endl;
}
};
int main(){
//此 persion 对象是在栈空间
Persion persion;
persion.m_id = 10;
persion.m_height = 30;
persion.m_age = 20;
cout << "&persion: " << &persion <<endl;
cout << "&persion.m_id: " << &persion.m_id <<endl;
cout << "&persion.m_age: " << &persion.m_age <<endl;
cout << "&persion.m_height:" << &persion.m_height <<endl;
return 0 ;
}
>>结果
&persion: 0x61fe14
&persion.m_id: 0x61fe14
&persion.m_age: 0x61fe18
&persion.m_height:0x61fe1c
成员变量内存排布分析
内存地址 | 内存数据 | ||
&persion | &persion.m_id | 0X00E68B60 | 10 |
0X00E68B61 | |||
0X00E68B62 | |||
0X00E68B63 | |||
&persion.m_age | 0X00E68B64 | 20 | |
0X00E68B65 | |||
0X00E68B66 | |||
0X00E68B67 | |||
&persion.m_height | 0X00E68B68 | 30 | |
0X00E68B69 | |||
0X00E68B6A | |||
0X00E68B6B |
对象直接访问成员变量
Persion persion;
persion.m_id = 10;
persion.m_height = 30;
persion.m_age = 20;
生成的汇编是:
mov dword ptr [ebp-14h],0Ah //ebp-14h是persion对象的地址值
mov dword ptr [ebp-10h],14h // ebp-10h - ebp-14h = 4个字节
mov dword ptr [ebp-0Ch],1Eh
通过指针间接访问所指向对象的成员变量
1、从指针中取出对象的地址
2、利用对象的地址+成员变量的偏移量计算成员变量的地址
3、根据成员变量的地址访问成员变量的存储空间
Persion *p = & persion;
p->m_id = 10;
p->m_height = 10;
p->m_age = 10;
p->display()
//Persion *p = & persion;
lea eax,[ebp-14h] //将persion对象的地址取出赋值给eax,ebp-14h是persion对象的地址,
mov dword ptr [ebp-20h],eax //ebp-20h是指针p的地址
//exa存储的是persion对象的地址,也就是persion.m_id的地址
// p->m_id = 10;
mov eax, dword ptr [ebp-20h] //取出指针变量p存储的内容取出放入persion对象地址
mov dword ptr [eax],0Ah //将10放入persion对象的存储空间。
注释:[]里放的是地址,[eax]中eax是地址值,dword ptr [ebp-20h] 从某个存储空间取出一个地址值说明是个指针的存储空间,可以推出ebp-20h是个指针的地址值,[ebp-20h]是指针,dword ptr [ebp-20h]是指针存储的值
mov eax, dword ptr [ebp-20h]
mov dword ptr [eax+4],0Ah // eax+4就是第二个成员变量的地址值
mov eax, dword ptr [ebp-20h]
mov dword ptr [eax+8],0Ah
mov eax, dword ptr [ebp-20h]
call 003B141F
一个p->dispaly() 的demo
class Persion
{
public:
int m_id;
int m_age;
int m_height;
void display(){
cout << "id:" <<m_id << "age:" << m_age << "height:" << m_height<<endl;
}
};
int main(){
Persion persion;
persion.m_id = 10;
persion.m_height = 30;
persion.m_age = 20;
persion.display(); // id:10 age:20 height:30
Persion *p = (Persion *) &persion.m_age;
p->m_id = 40;
p->m_age = 50;
persion.display(); // id:10 age:40 height:50 因为将persion对象的地址传给display函数的this
p->display();// id:40 age:50 height:其他数据。因为将指针p里面存储的地址值传递给display函数的this
}
p->display(),p指向的是persion地址+4,即m_age的地址,那么在dispaly中的this->m_id,this->m_age,this->m_height,的偏移量自动加了4个字节,最终导致m_height的偏移量超过12.