this 指针理解和应用

this指针只能在一个类的成员函数中调用,它表示 当前对象 的地址。(使用它可以调用对象的成员)
下面是一个例子:
    void Date::setMonth( int mn )
    {
     month = mn; //这三句是等价的(month是类成员变量)
     this->month = mn;
     (*this).month = mn;
    }

1. this只能在 成员函数 中使用。
全局函数,静态函数都不能使用this。
实际上,成员函数默认 第一个参数 为T* const register this。
如:
class A
{
public:
    int func(int p)
    {
     }
};
其中,func的原型在编译器看来应该是:
int func(A* const register this, int p);
2. 由此可见,this在成员函数的开始前构造的,在成员的结束后清除。
这个生命周期同任一个函数的参数是一样的,没有任何区别。
当调用一个类的成员函数时,编译器 将 类的指针 作为 函数的this参数 传递进去。如:
A a;
a.func(10);
此处,编译器将会编译成: A::func(&a, 10);

看起来和静态函数没差别,不过,区别还是有的。编译器通常会对this指针做一些优化的,
因此,this指针的传递效率比较高--如vc通常是通过ecx寄存器来传递this参数。

3. 回答
#1:this指针是什么时候创建的?
this在成员函数的开始执行前构造的,在成员的执行结束后清除。

#2:this指针存放在何处? 堆,栈,全局变量,还是其他?
this指针会因编译器不同,而放置的位置不同。可能是栈,也可能是寄存器,甚至全局变量。

#3:this指针如何传递给类中函数的?绑定?还是在函数参数的首参数就是this指针.那么this指针又是如何找到类实例后函数的?
this是通过函数参数的首参数来传递的。this指针是在调用之前生成的。类实例后的函数,没有这个说法。
类在实例化时,只分配类中的变量空间,并没有为函数分配空间。自从类的函数定义完成后,它就在那儿,不会跑的。

#4:this指针如何访问类中变量的?
如果不是类,而是结构的话,那么,如何通过结构指针来访问结构中的变量呢?如果你明白这一点的话,那就很好理解这个问题了。
在C++中,类和结构是只有一个区别的:类的成员默认是private,而结构是public。
this是类的指针,如果换成结构,那this就是结构的指针了。

#5:我们只有获得一个对象后,才能通过对象使用this指针,如果我们知道一个对象this指针的位置可以直接使用吗?
this指针只有在成员函数中才有定义。因此,你获得一个对象后,也不能通过对象使用this指针。
所以,我们也 无法知道一个对象的this指针 的位置(只有在成员函数里才有this指针的位置)。
注意:当然,在成员函数里,你是可以知道this指针的位置的(可以&this获得),也可以直接使用的。(因为this指针是成员函数的参数撒)

#6:每个类编译后,是否创建一个类中函数表保存函数指针,以便用来调用函数?
普通的类函数(不论是成员函数,还是静态函数),都不会创建一个函数表来保存函数指针的。只有虚函数才会被放到函数表中。
但是,既使是虚函数,如果编译器能明确知道调用的是哪个函数,编译器就不会通过函数表中的指针来间接调用,而是会直接调用该函数。

# 7:这些编译器如何做到的?8:能否模拟实现?
知道原理后,这两个问题就很容易理解了。
其实,模拟实现this的调用,在很多场合下,很多人都做过。
例如,系统回调函数。系统回调函数有很多,如定时,线程啊什么的。

举一个线程的例子:
class A{
int n;
public:
static void run(void* pThis){
A* this_ = (A*)pThis;
this_->process();
}
void process(){}
};

main(){
A a;
_beginthread( A::run, 0, &a );
}

这里就是定义一个静态函数来模拟成员函数。

也有许多C语言写的程序,模拟了类的实现。如freetype库等等。
其实,有用过C语言的人,大多都模拟过。只是当时没有明确的概念罢了。
如:
typedef struct student{
int age;
int no;
int scores;
}Student;
void initStudent(Student* pstudent);
void addScore(Student* pstudent, int score);
...
如果你把 pstudent改成this,那就一样了。

它相当于:
class Student{
public:
int age; int no; int scores;
void initStudent();
void addScore(int score);
}

const常量可以有物理存放的空间,因此是可以取地址的


//this指针是在创建对象前创建.
this指针放在栈上,在编译时刻已经确定.
并且当一个对象创建后,并且运行整个程序运行期间只有一个this指针.

 

编译分析:

我在一个控制台程序中使用了_beginthreadex函数,并包含了PROCESS.h头文件.
但总是编译错误:error C2065: '_beginthreadex' : undeclared identifier.上网一查,才知道需要做以下设置:
工程->设置->C/C++->Code Generation->Use run-time libray->选 Debug Multithread(多线程),或 Multithread.

 

 

补充:(例子)(包含对类成员变量的访问)

#include "stdafx.h"
#include "iostream.h"

class CNullPointCall
{
public:
    static void Test1();
    void Test2();
    void Test3(int iTest);
    void Test4();
 
private:
    static int m_iStatic;
    int m_iTest;
};

int CNullPointCall::m_iStatic = 0;    //注意加上int 声明静态变量的值;可以变化,但是不能在类外声明;

void CNullPointCall::Test1()
{
    cout << m_iStatic << endl;
}

void CNullPointCall::Test2()
{
    cout << "Very Cool!" << endl;
}

void CNullPointCall::Test3(int iTest)
{
    cout << iTest << endl;
}

void CNullPointCall::Test4()
{
    cout << m_iTest << endl;
}

 

int main(int argc, char* argv[])
{
 CNullPointCall *pCall = NULL;
 pCall->Test1();    //静态函数,相当于CNullPointCall::Test1() 式的调用,不会传递this指针
 pCall->Test2();    //会传递this指针,但是函数体内没有调用成员变量,所以没有用this指针
 pCall->Test3(100); //同函数2的调用
 pCall->Test4();    //会传递this指针,而且成员函数里面用到了this指针,但是此时this指针赋值为NULL 所以系统运行到这里会崩溃
 //printf("Hello World!/n");
 return 0;
}

/*

注意:pCall只是一个调用类CNullPointCall 成员函数的形式,和this指针没有一点关系;this只能在类的非静态成员函数中使用;

pCall 只是用来调用成员函数的,例如:

 D *d = NULL;
 d->bPrintf();
 ((D*)0)->bPrintf();

d可以实现函数的调用;但是((D*)0)也可以实现类成员函数调用;把0 强制转化成D*类型就可以了     

*/

经过细心的比较就可以发现,call 4那行代码跟其他3行代码的本质区别:类CNullPointCall的成员函数中用到了this指针。
    对于类成员函数而言,并不是一个对象对应一个单独的成员函数体,而是此类的所有对象共用这个成员函数体。 当程序被编译之后,此成员函数地址即已确定。而成员函数之所以能把属于此类的各个对象的数据区别开, 就是靠这个this指针。函数体内所有对类数据成员的访问, 都会被转化为this->数据成员的方式。
    而一个对象的this指针并不是对象本身的一部分,不会影响sizeof(“对象”)的结果。this作用域是在类内部,当在类的非静态成员函数中访问类的非静态成员的时候,编译器会自动将对象本身的地址作为一个隐含参数传递给函数。也就是说,即使你没有写上this指针,编译器在编译的时候也是加上this的,它作为非静态成员函数的隐含形参,对各成员的访问均通过this进行。
    对于上面的例子来说,this的值也就是pNull的值。也就是说this的值为NULL。而Test1()是静态函数,编译器不会给它传递this指针,所以call 1那行代码可以正确调用(这里相当于CNullPointCall::Test1());对于Test2()和Test3()两个成员函数,虽然编译器会给这两个函数传递this指针,但是它们并没有通过this指针来访问类的成员变量,因此call 2和call 3两行代码可以正确调用;而对于成员函数Test4()要访问类的成员变量,因此要使用this指针,这个时候发现this指针的值为NULL,就会造成程序的崩溃。   
    其实,我们可以想象编译器把Test4()转换成如下的形式:

void CNullPointCall::Test4(CNullPointCall *this)
{
    cout << this->m_iTest << endl;
}

    而把call 4那行代码转换成了下面的形式:

CNullPointCall::Test4(pNull);

    所以会在通过this指针访问m_iTest的时候造成程序的崩溃。

你可能感兴趣的:(this 指针理解和应用)