面试---内存偏移

来源:互联网 发布:桌面软件开发架构 编辑:程序博客网 时间:2024/06/06 01:12

下面程序中pb->func();的输出结果?

#include <iostream>#include<stdio.h>using namespace std;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;};    ~N() {};    void func()    {        cout<<c<<endl;    }//private:    int c;};int main(){    M m;    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;    return 0;}

结果:

1################0x28ff040x28ff040x28ff04################000000000000000400000000################Process returned 0 (0x0)   execution time : 0.173 sPress any key to continue.

暂且不讨论该程序设计有多么糟糕,但程序主要考察关于类对象成员调用的机制,关于这方面,在《深入理解C++对象模型》中有详解。

这里主要涉及到两方面:一是对象调用成员函数时会将调用对象与函数绑定;二是对象访问成员是根据该成员距离对象的偏移量来访问的!!!!,而不是根据成员名来访问,所谓偏移量,就是告诉你一个特定的成员位置距离对象的起点有多少个字节。

上面程序,内存中实例化了一个M类对象,然后将该地址强制转换成一个N类地址,即将该对象的地址内容强制看成一个N类对象。pb为N类的指针,理所当然调用的是N类中的fun()函数(可以跟多态的情形相比较),当调用fun()函数时,调用对象与该函数进行绑定,即fun()函数中隐含的形参this指针初始化为调用对象(M类对象)的地址,假设为0xff80。然后fun()函数打印值c。这里要注意,对象在访问类成员时,编译器并没有存储该对象各个成员的实际地址,而是存储了其相对于当前对象首地址的偏移量,由于N类只有一个成员c,在编译阶段,编译器就记录了c对于N类对象的偏移量为0,故访问c时,便是访问当前对象地址this+偏移量0,注意,this在这里绑定的是M类对象的首地址,在M类中,偏移量为0的成员是a,故打印出a的值。

关于类成员偏移量的输出,可以用程序验证。

例如如下程序:将地址0强制转换为A类对象的地址,那么打印类成员m_a和m_b的地址便是他们的偏移量,如下分别输出0,0x4。

cout<<&((M*)0)->a<<endl;cout<<&((M*)0)->b<<endl;

关于成员指针!!!!

成员指针只是记录一个成员的偏移量,而非地址,因为类中没有地址,选择一个类的成员只是意味着在类中偏移,只有把这个偏移和具体对象的首地址结合,才能得到实际地址。

成员指针并不指向一个具体的内存位置,它指向的是一个类的特定成员,而不是指向一个特定对象的特定成员,最直接的理解是将其理解为一个偏移量。这个偏移量适用于某一类A的任何对象,换言之,如果一个A类对象的成员a距离起点的偏移量是4,那么任何其他A类对象中,a的偏移都是4字节。

啰嗦一大堆,总结一下就是两句话:

类对象访问其成员时,是根据该成员在类中的偏移量来访问的。类成员指针,可以理解为指向类数据成员的一个偏移量,而非地址。

参考:http://blog.csdn.net/wenhai_zh/article/details/10311335

0 0