this指针探秘
当时我初学C++的时候,觉得this简直是一个怪物,书本上说
this指针不存在于对象之中,因此sizeof(X)时不体现this的大小
但,根据我当时头脑中的一些概念,变量先定义后使用,凡是变量都可取地址
this指针就有了一些很“怪”的特征:没有定义,不许取地址,不能赋值,而且能够指向对象
不知道其他人是不是有相似的感觉,总之,我觉得this很神奇,于是也萌发一个一探究竟的欲望
也请教过一些人,无不是被K的灰头土脸,基本所有人都说这是一个无意义的问题,为什么无意义
我想,可能是即使你不了解它背后的一些东西,对使用来说,一点问题也没有,由此我倒是想到了
孔已己写回字,被一个伙计都看不起,我基本都快成孔已己了,其实我想,多会写几个回字倒也没
什么大了不起也不值得被人猛K,但是,不能只会写回字,对不对,除了写回字以外一无所长,
这就大大的糟糕了,做技术的也是一样,不能只钻牛角尖,但是偶尔钻一钻牛角尖我想也无伤大雅
好,说完我为什么要知道this指针到底是什么之后就进入正题
bj在它的著作(C++语言的设计与演化 p62)里说在早期的C++里
this是一个可以被赋值的东东,只是在继承在堆栈里很难处理,后来才被淘汰掉
class X{
//...
public:
X();
//...
};
X::X(){
this=my_alloc(sizeof(X));
//...
}
X x;//为x分配内存
既然可以为它赋值那么就意味着this可能是真实存在的这么一个变量
之后我又机会读到了深度探索C++对象模型,书中对this的描述是,this是一个函数参数
float manitude3d(const Point3d *_this){...};
float Point3d::manitude3d()const{...}
这两种方式是等价的,编译器在内部将后者转化为前者,因此
obj.magintude();变成了maginitude_7Point3dFv(&obj);
看完相关的章节,觉得自己对于C++是有了一定的理解,知道this为什么只能
在成员函数中使用,它是一个函数参数,函数参数能在定义它的函数外使用吗?当然不能
也许到这里理解的可能就够了,但是偏偏我这个人有点拧,我就想既然this是真实的变量,那我为什么不能取它地址?给它赋值?又过了一段时间,我开始学习汇编,用的是清华的《汇编语言》作者王爽,这真的是一本不错的书,通俗易懂,拿来入门真是合适不过了,以前我用的是冶金工业出版社的《80X86汇编语言程序设计》讲的我就是晕的一塌糊涂,由此我也想到了,一本好书的定义,应该是能让人一看就茅舍顿开,而一本垃圾书则相反,通过一段时间的学习后(这段时间我待业,刚好有足够的时间)我分别跟踪了VC6.0和BCB6.0中的成员函数执行过程,终于觉得是很久以来想不通的东西都明白了,很爽
先说VC6.0
当程序执行
x.foo();
lea ecx,dword ptr[ebp-4] //对象地址存储到ecx中
call @ILT +10(X::foo)(0040100f) //跳转到0040100f处
0040100f jmp X::foo //0040100f处的jmp跳转的函数真正的地址
void X::foo(){
//...
mov doword ptr[ebp-4],ecx
//将对象地址从ecx中读出,写入到foo的ebp-4处
//...
}
由此可见,在VC中对象地址是通过寄存器变量传递进成员函数,但是进入函数后做完一些初始化的工作以后
把对象地址写入到foo的ebp-4处,这个ebp-4不是调用前的ebp-4,这里存在着压栈等多种操作,很难一下说清楚
由此,了解了VC成员函数的调用过程,我们可以大胆做一些测试程序
void X::foo(X *p){
__asm{
mov eax,doword ptr[ebp+8]
mov dword ptr[ebp-4],eax
//this = p
}
this->a=10;//p->a=10;
}//偷梁换柱,this实际已经指向*p
void X::foo(){
X **p;
__asm{
lea eax,dword ptr[ebp-4]
mov dword ptr [ebp-8],eax
//p=&this
}
(*p)->a=10;//this->a=10;
}//p指向了this因此**p==*this
再说bcb6.0,当程序执行
x.foo();
lea eax,[ebp-0x04]
push eax //将对象地址压栈
call X::foo() //调用X::foo()