现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

浅谈一下this指针相关

2012-09-04 11:42 工业·编程 ⁄ 共 2883字 ⁄ 字号 暂无评论

    this指针指向的是当前对象的起始地址,这个大家都知道。this指针变量是编译器所维护的,对于程序员来说属于const,是一个定值。一般对象创建调用构造函数时,通过编译器在构造函数里‘偷偷’安插的代码完成this指针变量的赋值。所以下面的代码输出结果是一致的。

  1. #include <iostream>
  2. using namespace std;
  3. class Test
  4. {
  5. public:
  6.     Test()
  7.     {
  8.         cout<<this<<endl;
  9.     }
  10. };
  11. int main()
  12. {
  13.     Test test;
  14.     cout<<&test<<endl;
  15.     system("pause");
  16. }

现在谈一下this指针对于编译器的作用:
由于类成员函数不同于一般的函数,类成员函数一般要修改对象里的成员变量,对于c语言中一个函数要修改一个struct中变量的值一般是函数有一个结构体类型的参数,正如下面的代码:

  1. #include <iostream>
  2. using namespace std;
  3. struct Test
  4. {
  5. int a;
  6. int b;
  7. };
  8. void Change(Test * t)
  9. {
  10.     t->a=1;
  11.     t->b=2;
  12. }
  13. int main()
  14. {
  15.     Test test;
  16.     test.a=0;
  17.     test.b=0;
  18.     cout<<test.a<<endl;
  19.     cout<<test.b<<endl;
  20.     cout<<"after changed:"<<endl;
  21.     Change(&test);
  22.     cout<<test.a<<endl;//输出1
  23.     cout<<test.b<<endl;//输出2
  24.     system("pause");
  25. }

c语言中的函数通过类似上面的方法,修改结构体成员的值。而c++中则可以直接用如下的方式:

  1. #include <iostream>
  2. using namespace std;
  3. struct Test
  4. {
  5. int a;
  6. int b;
  7. void Change()
  8.     {
  9.         a=1;
  10.         b=2;
  11.     }
  12. };
  13. int main()
  14. {
  15.     Test test;
  16.     test.a=0;
  17.     test.b=0;
  18.     cout<<test.a<<endl;
  19.     cout<<test.b<<endl;
  20.     cout<<"after changed:"<<endl;
  21.     test.Change();
  22.     cout<<test.a<<endl;//输出1
  23.     cout<<test.b<<endl;//输出2
  24.     system("pause");
  25. }

上如方法比c语言显得优雅一些,但实际上test.Change();调用方式编译器的内部实现和Change(&test)相似的,甚至可以说比
Change(&test)要效率低些。其中this指针就扮演了&test相同作用的角色。对于类的声明,编译器获得了必要类对象的内存布局的信息,对于对象中各数据成员相对于对象起始地址的偏移量了如指掌了。如下代码:

  1. #include <iostream>
  2. using namespace std;
  3. class Test
  4. {
  5. public:
  6. int a;
  7. int b;  
  8. };
  9. int main()
  10. {
  11.     Test test;
  12.     printf("%d/n",&Test::a);//输出0
  13.     printf("%d/n",&Test::b);//输出4
  14. //不要用cout,可能是operator<<实现问题,
  15. //cout<<&Test::b变成了判断是否为真从而
  16. //得不到正确的结果
  17. //cout<<&Test::a<<endl;
  18. //cout<<&Test::b<<endl;
  19.     system("pause");

每个类的对象在内存的布局中包含了类中所声明的非静态的数据成员,一旦知道了对象的起始地址,也就说this值一旦确定,编译器通过this指针+偏移量就能访问和操作类成员变量的值了。所以this指针的作用之一也在于此。接着上面说到类成员函数
是如何访问类成员变量的,其实分析到这儿,相信您也已经基本明白了。对,编译在实现成员函数调用时,隐式的传入this指针

  • void Change()
  • {
  •     a=1;//被编译器扩展成this+offsset,再通过成员变量a的类型信息,就可以确定a映射到内存中的区域了,进而
  •     b=2;//对那块区域进行操作。
  • }
  • 类似下面的代码,对类成员变量的访问一样:
    1. #include <iostream>
    2. using namespace std;
    3. class Test
    4. {
    5. public:
    6.     Test():a(1),b(2){}
    7. int a;
    8. private:
    9. int b;  
    10. };
    11. int main()
    12. {
    13.     Test test;
    14. //a相对于对象的起始地址偏移为0
    15. //也就是说从对象的起始地址起往下
    16. //涵盖4个字节的内存是a所对应的内存
    17.     cout<<*(int*)&test<<endl;//输出1
    18. //偏移4个字节后,再往下涵盖4个字节就是b对应
    19. //内存,注意b是private的,通过指针是可以访问
    20. //对象的私有变量的。
    21.     cout<<*(int*)((int)&test+4)<<endl;//输出2
    22.     system("pause");
    23. }

    所以,对于this指针编译器主要用来访问对象中的数据成员的。

  • 另外由于this指针存在和c++编译器对类对象的处理方式,所以指向类非静态成员变量的指针,也不是真正意义上的指针了,它的值是一个偏移量,不是一个地址值,如下面的代码:
    1. #include <iostream>
    2. using namespace std;
    3. class Test
    4. {
    5. public:
    6.     Test():a(1),b(2){}
    7. int a;
    8. int b;  
    9. };
    10. typedef int Test::*Pmeb;
    11. int main()
    12. {
    13.     ios::sync_with_stdio();
    14.     Test test;
    15.     Pmeb p=&Test::b;
    16.     printf("%d/n",p);//输出4
    17.     cout<<test.*p<<endl;//输出2
    18.     system("pause");
    19. }

    还有指向类中非静态成员函数的指针,完成函数调用必须通过类的对象,由于隐式传入this指针的原因,如下代码:

    1. #include <iostream>
    2. using namespace std;
    3. class Test
    4. {
    5. public:
    6.     Test():a(1),b(2){}
    7. int a;
    8. int b;
    9. void Print()
    10.     {
    11.         cout<<a<<endl;
    12.         cout<<b<<endl;
    13.     }
    14. };
    15. typedef void (Test::*Pfmeb)();
    16. int main()
    17. {
    18.     Test test;
    19.     Pfmeb p=&Test::Print;
    20.     (test.*p)();
    21.     system("pause");
    22. }

    像static成员函数只能访问static成员变量和调用static函数的原因也是由于this指针的原因,static成员函数没有this指针。

  • 给我留言

    留言无头像?