effective c++ 15 内存偏移---对象是如何调用成员的

内存偏移

先看看官方的解释:
计算机汇编语言中的偏移量定义为:把存储单元的实际地址与其所在段的段地址之间的距离称为段内偏移,也称为“有效地址或偏移量”。
段地址左移四位,与有效地址相加,就构成了逻辑地址。一般而言,段地址是cpu自己独立编制的,但是偏移量是程序员编写的。偏移量就是程序的逻辑地址与段首的差值。
说白了偏移量也就是一个相对位置量罢了。
如果某个内存区的地址使用一个明确的类型指针例如int*、long*来进行保 存,那么指针偏移时地址的偏移数以类型占的字节数为基本单位进行偏移,例如int p变量+1的时候实际上跳过的是sizeof(int)的类型字节数的地址为单位进行跳跃——也就是跳跃4个地址,但如果是不确认类型的情况下使用void来保存,则必须指定每次跳跃的准确地址数。
偏移—普通变量
void fun1(){
int *data = (int *) malloc(sizeof(int) * 4);
data[0] = 1;
data[1] = 2;
data[2] = 3;
data[3] = 4;
printf("%d\t%d\n", *data, *(data + 1));
}

void fun2(){
void *data = (void *)malloc(sizeof(int) * 4);
(int)(data + sizeof(int) * 0) = 1;
(int)(data + sizeof(int) * 1) = 2;
(int)(data + sizeof(int) * 2) = 3;
(int)(data + sizeof(int) * 3) = 4;
printf("%d\t%d\n", (int)data, (int)(data + sizeof(int) * 3));
}

void fun3(){
int i;
void *data = (void *)malloc(sizeof(int) * 4);
int *data2 = (int *)malloc(sizeof(int) * 4);
printf("\n");
for(i = 0; i < 4; i++) {
printf(“test1:%d\n”, data + i);
}
printf("\n");
for(i = 0; i < 4; i++) {
printf(“test2:%d\n”, data2 + i);
}
}

int main(){
fun1();
fun2();
fun3();
return 0;
}
在这里插入图片描述
偏移—对象
class M
{
public:
M() { a = 1; b = 2; };
~M() {};
void func()
{
cout << a << " " << b << endl;
}
//private:
int a;
int b;
};

class N
{
public:
N() { c = 3; d = 4; };
~N() {};
void func()
{
cout << c << endl;
}
//private:
int d;
int c;

};

int maint()
{
M m;
int *p = (int *)&m;
cout << sizeof(M) << endl;
cout << *(p+1) << endl;
N pb = (N)(&m); //!!!
pb->func();
cout << “################” << endl;
cout << &m << endl;
cout << (&m.a) << endl;
cout << pb << endl;
cout << “################” << endl;
printf("%p\n", &M::a);//%p 格式转为指针,输出地址
printf("%p\n", &M::b);
printf("%p\n", &N::c);
cout << “################” << endl;

system("pause");

return 0;
}
在这里插入图片描述
在这里插入图片描述
暂且不讨论该程序设计有多么糟糕,但程序主要考察关于类对象成员调用的机制,关于这方面,在《深入理解C++对象模型》中有详解。这里主要涉及到两方面:一是对象调用成员函数时会将调用对象与函数绑定;二是对象访问成员是根据该成员距离对象的偏移量来访问的!!!!,而不是根据成员名来访问,所谓偏移量,就是告诉你一个特定的成员位置距离对象的起点有多少个字节。
上面程序,内存中实例化了一个M类对象,然后将该地址强制转换成一个N类地址,即将该对象的地址内容强制看成一个N类对象。pb为N类的指针,理所当然调用的是N类中的fun()函数(可以跟多态的情形相比较),当调用fun()函数时,调用对象与该函数进行绑定,即fun()函数中隐含的形参this指针初始化为调用对象(M类对象)的地址,假设为0xff80。然后fun()函数打印值c。这里要注意,对象在访问类成员时,编译器并没有存储该对象各个成员的实际地址,而是存储了其相对于当前对象首地址的偏移量,由于N类只有一个成员c,在编译阶段,编译器就记录了c对于N类对象的偏移量为1,故访问c时,便是访问当前对象地址this+偏移量1,注意,this在这里绑定的是M类对象的首地址,在M类中,偏移量为1的成员是b,故打印出b的值。
总结:
1.对象调用成员函数时会将调用对象与函数绑定;
2.对象访问成员是根据该成员距离对象的偏移量来访问的!!!!,而不是根据成员名来访问,所谓偏移量,就是告诉你一个特定的成员位置距离对象的起点有多少个字节。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

发如雪-ty

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值