面试---内存偏移
2015-09-27 17:17
246 查看
下面程序中pb->func();的输出结果?
结果:
暂且不讨论该程序设计有多么糟糕,但程序主要考察关于类对象成员调用的机制,关于这方面,在《深入理解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。
关于成员指针!!!!
成员指针只是记录一个成员的偏移量,而非地址,因为类中没有地址,选择一个类的成员只是意味着在类中偏移,只有把这个偏移和具体对象的首地址结合,才能得到实际地址。
成员指针并不指向一个具体的内存位置,它指向的是一个类的特定成员,而不是指向一个特定对象的特定成员,最直接的理解是将其理解为一个偏移量。这个偏移量适用于某一类A的任何对象,换言之,如果一个A类对象的成员a距离起点的偏移量是4,那么任何其他A类对象中,a的偏移都是4字节。
啰嗦一大堆,总结一下就是两句话:
参考:http://blog.csdn.net/wenhai_zh/article/details/10311335
#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 ################ 0x28ff04 0x28ff04 0x28ff04 ################ 00000000 00000004 00000000 ################ Process returned 0 (0x0) execution time : 0.173 s Press 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
相关文章推荐
- PHP程序员面试 切忌急功近利(更需要注重以后的发展)
- C#常见算法面试题小结
- php 面试碰到过的问题 在此做下记录
- asp.net 面试+笔试题目第1/2页
- asp.net 面试 笔试题目[附答案]第1/3页
- 面试:(设计,架构)
- PHP中级面试经历
- 戴维营教育2015年iOS暑期班笔试面试基础考核题
- 程序员编程面试取胜的8个技巧
- PHP相关面试中最经常涉及的12个问题
- 面试时,你会问面试官哪些问题?
- asp.net面试中的四十一个经典题目
- 网络工程师面试常见问题
- 腾讯社招面试经历
- java基础面试题 - java基础(1)
- 2013阿里巴巴安全工程师实习生招聘笔试小结
- 工作流引擎面试记录及未来发展
- 3个CCIE对一个工程师的面试题
- 今天面试IBM CSDL
- 职场动态赢得面试机会的8个技巧