zoukankan      html  css  js  c++  java
  • 第5课 引用的本质分析

    引用作为变量别名而存在,因此在一些场合可以代替指针

    引用相对于指针来说具有更好的可读性和实用性

    swap函数的实现对比如下:

    注意:

      函数中的引用形参不需要进行初始化。

    示例程序如下:

    形参没有初始化,而是在第15行调用的时候对引用形参进行初始化。

     const引用:

    当使用常量对const引用进行初始化时,C++编译器会为常量值分配空间,并将引用名作为这段空间的别名。

    例:

    结论:

      使用常量对const引用初始化后将生成一个只读变量。普通引用不能使用常量值进行初始化,但是const引用可以。

    我们不能直接改变const引用的值,但是可以通过取地址的方式间接的改变这块内存的值。

    示例程序:

     1 #include <stdio.h>
     2 
     3 void Example()
     4 {
     5     printf("Example:
    ");
     6     
     7     int a = 4;
     8     const int& b = a;
     9     int* p = (int*)&b;
    10     
    11     //b = 5;
    12     
    13     *p = 5;
    14     
    15     printf("a = %d
    ", a);
    16     printf("b = %d
    ", b);
    17 }
    18 
    19 void Demo()
    20 {
    21     printf("Demo:
    ");
    22     
    23     const int& c = 1;
    24     int* p = (int*)&c;
    25     
    26     //c = 5;
    27     
    28     *p = 5;
    29     
    30     printf("c = %d
    ", c);
    31 }
    32 
    33 int main(int argc, char *argv[])
    34 {
    35     Example();
    36     
    37     printf("
    ");
    38     
    39     Demo();
    40 
    41     return 0;
    42 }

    运行结果如下:

      可以看到Example函数中通过指针p可以改变内存空间的值,最终影响到了a和b的值,其实它们指的是同一块内存空间,在这个函数中我们也可以直接改变a的值。因为a并不是const的。

     引用有自己的存储空间吗?

    示例程序如下:

     1 #include <stdio.h>
     2 
     3 struct TRef
     4 {
     5     char& r;
     6 };
     7 
     8 int main(int argc, char *argv[])
     9 { 
    10     char c = 'c';
    11     char& rc = c;
    12     TRef ref = { c };
    13     
    14     printf("sizeof(char&) = %d
    ", sizeof(char&));
    15     printf("sizeof(rc) = %d
    ", sizeof(rc));
    16     
    17     printf("sizeof(TRef) = %d
    ", sizeof(TRef));
    18     printf("sizeof(ref.r) = %d
    ", sizeof(ref.r));
    19 
    20     return 0;
    21 }

    执行结果:

    char&代表char的引用,所以占用一个字节,rc也是char的引用,占用一个字节,ref.r是char的引用,也占用一个字节。

    sizeof(TRef)占用四个字节,这让我们联想到了指针。

    引用的内部实现:引用在C++中的内部实现是一个指针常量,具体如下。

     引用的存储空间:

    示例程序:

     1 #include <stdio.h>
     2 
     3 struct TRef
     4 {
     5     char* before;
     6     char& ref;
     7     char* after;
     8 };
     9 
    10 int main(int argc, char* argv[])
    11 {
    12     char a = 'a';
    13     char& b = a;
    14     char c = 'c';
    15 
    16     TRef r = {&a, b, &c};
    17 
    18     printf("sizeof(r) = %d
    ", sizeof(r));
    19     printf("sizeof(r.before) = %d
    ", sizeof(r.before));
    20     printf("sizeof(r.after) = %d
    ", sizeof(r.after));
    21     printf("&r.before = %p
    ", &r.before);
    22     printf("&r.after = %p
    ", &r.after);
    23 
    24     return 0;
    25 }

    执行结果如下:

    根据计算,可以得到结构体中的ref占用了4个字节。从地址的判断也可以得出ref占用了4个字节。

     上述程序在windows下的反汇编如下:

    引用的意义:

    函数返回引用示例程序如下:

     1 #include <stdio.h>
     2 
     3 int& demo()
     4 {
     5     int d = 0;
     6     
     7     printf("demo: d = %d
    ", d);
     8     
     9     return d;
    10 }
    11 
    12 int& func()
    13 {
    14     static int s = 0;
    15     
    16     printf("func: s = %d
    ", s);
    17     
    18     return s;
    19 }
    20 
    21 int main(int argc, char* argv[])
    22 {
    23     int& rd = demo();
    24     int& rs = func();
    25     
    26     printf("
    ");
    27     printf("main: rd = %d
    ", rd);
    28     printf("main: rs = %d
    ", rs);
    29     printf("
    ");
    30     
    31     rd = 10;
    32     rs = 11;
    33     
    34     demo();
    35     func();
    36     
    37     printf("
    ");
    38     printf("main: rd = %d
    ", rd);
    39     printf("main: rs = %d
    ", rs);
    40     printf("
    ");
    41     
    42     return 0;
    43 }

      demo函数中相当于返回了局部变量的“指针”,这是有问题的。返回局部变量的引用是要禁止的。func函数中返回的是静态变量的引用。静态变量的存储空间不会由于函数调用的返回而被摧毁,因此,这样做是没有问题的。

    执行结果如下:

    第一次打印rd的值发生了很大的变化,这是因为26行函数的调用,改变了栈空间中的数据。第二次打印rd同理。

    小结:

      引用作为变量别名而存在旨在代替指针

      const引用可以使得变量具有只读属性

      引用在编译器内部使用指针常量实现

      引用的最终本质为指针

      引用可以尽可能的避开内存错误

  • 相关阅读:
    hibernate08--OpenSessionInView
    hibernate07--关联映射
    hibernate06--参数的绑定
    hibernate05--list和iterator
    hibernate04--三种状态之间的转换
    hibernate03增删改查
    hibernate02环境的搭建
    hibernate01ORM的引入
    mongoDB
    spring-boot(三) HowTo
  • 原文地址:https://www.cnblogs.com/wanmeishenghuo/p/9515093.html
Copyright © 2011-2022 走看看