zoukankan      html  css  js  c++  java
  • 2.this指针的理解

    this指针并不是对象的一部分,他是隐式的,当类的对象被创建时,他指向类对象,

    this指针是类的一个自动生成、自动隐藏的私有成员,它存在于类的非静态成员函数中,指向被调用函数所在的对象。全局仅有一个this指针,当一个对象被创建时,this指针就存放指向对象数据的首地址。

    根据以下程序来说明this指针
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    #include<iostream>
    using namespace std;
    class Point
    {
      private:
      int x,y;
      public:
      Point(int a,int b)
      {
        x=a;
        y=b;
      }
      void MovePoint(int a,int b)
      {
        x+=a;
        y+=b;
      }
      void print()
      {
        cout<<"x="<<x<<"y="<<y<<endl;
      }  
    };
    int main()
    {
      Point point1(10,10);
      point1.MovePoint(2,2);
      point1.print();
      return 0;
    }
    当对象point1调用MovePoint(2,2)函数时,即将point1对象的地址传递给了this指针。
    MovePoint函数的原型应该是 void MovePoint( Point *this, int a, int b);第一个参数是指向该类对象的一个指针,我们在定义成员函数时没看见是因为这个参数在类中是隐含的。这样point1的地址传递给了this,所以在MovePoint函数中便显式的写成:
    void MovePoint(int a, int b) { this->x +=a; this-> y+= b;}
    即可以知道,point1调用该函数后,也就是point1的数据成员被调用并更新了值。
    4. 关于this指针的一个经典回答:
    当你进入一个房子后,
    你可以看见桌子、椅子、地板等,
    但是房子你是看不到全貌了。
    对于一个类的实例来说,
    你可以看到它的成员函数、成员变量
    但是实例本身呢?
    this是一个指针,它时时刻刻指向你这个实例本身
    5.使用this指针要注意的事项
    相信大家对指针的用法已经很熟了,这里也不多说些定义性的东西了,只说一下指针使用中的注意事项吧。
    一.在定义指针的时候注意连续声明多个指针时容易犯的错误,例如int * a,b;这种声明是声明了一个指向int类型变量的指针a和一个int型的变量b,这时候要清醒的记着,而不要混淆成是声明了两个int型指针。
    二.要避免使用未初始化的指针。很多运行时错误都是由未初始化的指针导致的,而且这种错误又不能被编译器检查所以很难被发现。这时的解决办法就是尽量在使用指针的时候定义它,如果早定义的话一定要记得初始化,当然初始化时可以直接使用cstdlib中定义的NULL也可以直接赋值为0,这是很好的编程习惯。
    三.指针赋值时一定要保证类型匹配,由于指针类型确定指针所指向对象的类型,因此初始化或赋值时必须保证类型匹配,这样才能在指针上执行相应的操作。

    详细解析

    编辑
    在前面曾经提到过: 每个对象中的数据成员都分别占有存储空间,如果对同一个类定义了n个对象,则有n组同样大小的空间以存放n个对象中的数据成员。但是,不同对象都调用同一个函数代码段。
    那么,当不同对象的成员函数引用数据成员时,怎么能保证引用的是所指定的对象的数据成员呢?假如,对于例9.6程序中定义的Box类,定义了3个同类对象a,b,c。
    如果有a.volume( ) ,应该是引用对象a中的height,width和length,计算出长方体a的体积。
    如果有b.volume( ) ,应该是引用对象b中的height,width和length,计算出长方体b的体积。
    而现今都用同一个函数段,系统怎样使它分别引用a或b中的数据成员呢?在每一个成员函数中都包含一个特殊的指针,这个指针的名字是固定的,称为this指针。它是指向本类对象的指针,它的值是当前被调用的成员函数所在的对象的起始地址。
    例如,当调用成员函数a.volume时,编译系统就把对象a的起始地址赋给this指针,于是在成员函数引用数据成员时,就按照this的指向找到对象a的数据成员。例如volume函数要计算height*width*length的值,实际上是执行:
    (this->height)*(this->width)*(this->length)
    由于当前this指向a,因此相当于执行:
    (a.height)*(a.width)*( a.length)
    这就计算出长方体a的体积。
    同样如果有b.volume( ) ,编译系统就把对象b的起始地址赋给成员函数volume的this指针,显然计算出来的是长方体b的体积。this指针是隐式使用的,它是作为参数被传递给成员函数的。
    本来,成员函数volume的定义如下:
    int Box::volume( )
    {
    return (height*width*length);
    }
    C++把它处理为
    int Box::volume(Box *this)
    {
    return (this->height * this->width * this->length);
    }
    即在成员函数的形参表列中增加一个this指针。
    在调用该成员函数时,实际上是用以下方式调用的:
    a.volume(&a);
    将对象a的地址传给形参this指针。然后按this的指向去引用其他成员。
    需要说明: 这些都是编译系统自动实现的,编程序者不必人为地在形参中增加this指针,也不必将对象a的地址传给this指针。在需要时也可以显式地使用this指针。
    例如在Box类的volume函数中,下面两种表示方法都是合法的、相互等价的。
    return (height * width * length); //隐含使用this指针
    return (this->height * this->width * this->length); //显式使用this指针
    可以用*this表示被调用的成员函数所在的对象,*this就是this所指向的对象,即当前的对象。
    例如在成员函数a.volume( )的函数体中,如果出现*this,它就是本对象a。上面的return语句也可写成
    return((*this).height * (*this).width * (*this).length);
    注意*this两侧的括号不能省略,不能写成*this.height。
    所谓“调用对象a的成员函数f”,实际上是在调用成员函数f时使this指针指向对象a,从而访问对象a的成员。在使用“调用对象a的成员函数f”时,应当对它的含义有正确的理解。 [1] 

    应用参考

    编辑
    this指针只能在一个类的成员函数中调用,它表示当前对象的地址。下面是一个例子:
    1
    2
    3
    4
    5
    6
    7
    voidDate::setMonth(intmn)
    {
      month=mn;
      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指针无需显式储存内存中。只要存储对象的内存位置确定,对应的this指针就被确定了。
    #3:this指针如何传递给类中函数的?绑定?还是在函数参数的首参数就是this指针.那么this指针又是如何找到类实例后函数的?
    this是通过函数参数的首参数来传递的。this指针是在调用之前生成的。类实例后的函数,没有这个说法。类在实例化时,只分配类中的变量空间,并没有为函数分配空间。自从类的函数定义完成后,它就在那儿,不会跑的。
    #4:this指针如何访问类中变量的?
    如果不是类,而是结构的话,那么,如何通过结构指针来访问结构中的变量呢?如果你明白这一点的话,那就很好理解这个问题了。
    在C++中,struct是一种类类型,struct和class只有一个区别的:class的成员和继承默认的访问控制权限是private,而struct是public。
    this是class或public的对象的指针。
    #5:我们只有获得一个对象后,才能通过对象使用this指针,如果我们知道一个对象this指针的位置可以直接使用吗?
    this指针只有在非静态成员中才有意义。获得一个对象后,不需要在类外部使用this对其操作。应当注意this是一个右值(方法的一个隐式参数) [2]  ,不存在所谓的this的“位置”,只是this表示了对象的存储位置而已。&this违反语义规则,是错误的用法,不会编译通过。
    #6:每个类编译后,是否创建一个类中函数表保存函数指针,以便用来调用函数?
    一般来说,对于类成员函数(不论是静态还是非静态的成员函数)都不需要创建一个在运行时的函数表来保存。只有虚函数才会被放到函数表中。
    但是,即使是虚函数,如果编译器能明确知道调用的是哪个函数,编译器就不会通过函数表中的指针来间接调用,而是可以直接调用该函数
  • 相关阅读:
    取得窗口大小和窗口位置兼容所有浏览器的js代码
    一个简单易用的导出Excel类
    如何快速启动chrome插件
    网页表单设计案例
    Ubuntu下的打包解包
    The source file is different from when the module was built. Would you like the debugger to use it anyway?
    FFisher分布
    kalman filter
    Group delay Matlab simulate
    24位位图格式解析
  • 原文地址:https://www.cnblogs.com/secd/p/13200298.html
Copyright © 2011-2022 走看看