• C++指针与引用(Pointers OR References)


    一、Pointers

      Pointer是指针,可以用来指向任何一个objects,包括一般变量:

    1 int  i = 3;
    2 int * pi = &i;
    3 cout << pi << endl; // 0x0064FDF0
    4 cout << *pi << endl; // 3

      此时pi本身内含i的地址,要取出pi所指向的object,可以使用*运算符(dereference operator).Pointer也可以用来指向任何一个class type objects。由于下面的pPoint指向一整个大结构(一个object),如果要取用其中的members(data members 或member functions都可以,只要他们的封装等级是public),必须使用—>运算符(arrow operator),例如:

    1 class CPoint { public: float _x, _y, _z; };
    2 CPoint  * pPoint = new CPoint;
    3 cout << pPoint << endl; // 0x00770560
    4 pPoint->_x = 9.28;
    5 cout << pPoint->_x << endl; // 9.28

      Pointer 甚至可以指向一个不明对象(void):

    1 void * pv;
    2 pv = malloc(1024); // 配置 1024 bytes(来自 heap)
    3 cout << pv << endl; // 0x00760A14

      此时如果要提取 pv 所指的对象,不可以,会出现编译出错:

    1 cout << *pv << endl; // error C2100: illegal indirection

      也说是说,pointer本身没有意义,它的意义来自于它的类型,因此,将pointer前进一个单位,究竟是前进多少个bytes呢?那要看pointer的类型,如果将int *pi和CPoint *pPoint各加1,得到:

    1 cout << ++pi << endl; // 0x0064FDF4,比原先增加 4
    2 cout << ++pPoint << endl; // 0x0077056C,比原先增加 12

      这是因为在32位的系统中int为4 bytes,而我们设计的CPoint里面有三个float数据,大小为12bytes,所以各指针累加1时,分别前进4bytes和12bytes。如果把一个指向不明对象的指针加1,会得到什么结果呢?不会有结果,只会编译出错:

    1 cout << ++pv << endl; // error C2036: 'void *' : unknown size

      当然,如果你做了强转型(cast)动作,就可以解决“不明对象”的问题,因为你赋予了该指针一个明确的类型,例如:

    1 double * pd = (double*)pv; // 强转型。double is 8 bytes.
    2 cout << pd << endl; // 0x00760A14
    3 cout << ++pd << endl; // 0x00760A1C,比原先增加 8

      下表是上述验证结果的一个整理:

       当我们开始设计classes继承体系,有许多时候需要把一个pointer指向一个类型不符的object(但彼此类型又有继承的关系存在,这其实正是polymorphism的一个精髓),这时候类型的转换就非常重要。强制转型太过粗暴,在不够安全的时候仍然强转换,存在风险。C++有其它更精致的转型工具,我们后续再谈。

      Pointer不但可以指向object,还可以指向class的data members或member functions。它们的形式有点怪,结果也可能出人意外,这些问题我们后续再谈。

    二、References

      与pointer常常相提并论,并且常常被混淆不清的是所谓的reference。Reference(&)像是一个常数指针,可以被自动提取(dereference)。下面这个例子就是使r成为x的一个reference:

    1 int x;
    2 int& r = x; // r is a reference of x

      当一个refernce产生,它必须被初始化为某个原已存在的object,像上面那样,如果我写:

    1 int& q = 12;

      那么编译器会先配置一块int内存空间,将内容设为12,然后把q这个reference“捆绑”到该空间上。重点是,任何reference都必须被“捆绑”到某一个空间,成为一个"化身“。当你处理该reference,你就是在处理那个被捆绑的空间。如果:

    1 int x = 0;
    2 int& r = x; // r is a reference of x
    3 int* p = &x; // p is a pointer to x
    4 r++; // 请注意:sizeof(r) == sizeof(x)

      那么r和x的现值都为1,因为增加r的值就是增加x 的值。

       面对reference,最简单的想像就是,把它幻想为一个形式漂亮的pointer。这个形式漂亮的pointer好处是,我们不需要担心它是否被初始化(编译器会强迫做),也需要担心何提取(dereference)它(同样的,编译器会负责)。Refernce虽然在本质上是一个指针,在形式却是个object。也就是因为其形式漂亮,而本质实用(用于call by refernce),所以refernce常被用于函数的参数列表(arguments list)和回传值(return value)。下面就是个例子:

      

    复制代码
     1 int* funcl(int* x)
     2 {
     3     (*x)++;
     4     return x;
     5 }
     6 
     7 int& func2(int& x)
     8 {
     9     x++;
    10     return x;
    11 }
    12 
    13 int main()
    14 {
    15    int a=0;
    16    //ugly but explictit,你可以你可以清楚看到传給 func1() 的是个指针。
    17    //传回值的形式也很「难看」。
    18    cout<<*funcl(&a)<<endl;
    19    // clean but hidden。传給 func2() 的其实是个指针(借助 reference)。
    20    // 但你看不出來。传回的也是指针(借助 reference),你也看不出來。
    21    cout<endl;
    22    23     return 0;
    24 }
    复制代码

     

  • 相关阅读:
    元素内容必须由格式正确的字符数据或标记组成
    Kafka监控工具,LinkedIn详解
    努力一周,开源一个超好用的接口Mock工具——Msw-Tools
    个人设计web前端大作业 基于html5制作美食菜谱网页设计作业代码
    接口注意事项---再次巩固,多看看不会亏!
    【matplotlib基础】--结合地图
    spring boot网上眼镜商场毕业设计-附源码241659
    一键部署k8s集群
    C++之this指针总结(二百二十)
    【数据库】SQL 表、索引、视图的创建修改与删除
  • 原文地址:https://www.cnblogs.com/ruanchunyi/p/18169059