欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C++中引用的本质分析

程序员文章站 2022-04-09 09:22:48
1,引用的意义: 1,引用作为变量别名而存在,因此在一些场合可以代替指针; 1,变量的另一个表现形式; 2,交换函数时,可代替指针; 2,引用相对于指针来说具有更好的可读性和实用性; 1,指针类似手动挡车,引用类似于自动挡车; 3,引用实现交换函数; 1,函数中的引用形参不需要进行初始化; 1,调用 ......

1,引用的意义:

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

       1,变量的另一个表现形式;

       2,交换函数时,可代替指针;

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

       1,指针类似手动挡车,引用类似于自动挡车;

    3,引用实现交换函数;

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

           1,调用函数的时候才初始化;

          

2,const 引用:

    1,代码示例:

1 int a = 4;
2 const int& b = a;
3 int* p = (int*)&b;  // 等价于取 a 的地址;
4 
5 b = 5;  // error,只读变量;
6 *p = 5;  // ok,修改变量 a 的值;

    2,在 c++ 中可以声明 const 引用;

    3,const type& name = var;

       1,只有这样一种方式,不想 const 指针有四种方式;

    4,const 引用让变量拥有只读属性;

       1,引用对象是常量还是变量可以决定其所能参与的操作,但对于引用本身         是不是一个常量未做限定;

       2,因为引用对象可能是个非常量,所以允许通过其他途径改变它的值;

      

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

    1,代码示例:

const int& b = 1;  // ok,产生空间,值为 1,别名为 b,生成只读变量;
       
int* p = (int*)&b;

b = 5;  // error,只读变量;
*p = 5;  // ok,修改变量 a 的值;

       1,这个分配的空间的别名是一个临时变量;

    2,结论:

       1,使用常量对 const 引用初始化后将生成一个只读变量;

   

4,引用的特殊意义实例分析:

    1,main.cpp 文件:

 1 #include <stdio.h>
 2 
 3 void example()
 4 {
 5     printf("example:\n");
 6     
 7     int a = 4;
 8     const int& b = a;  // 只读变量;
 9     int* p = (int*)&b;
10     
11     //b = 5;  // error: assignment(赋值) of read-only reference 'b';
12     
13     *p = 5;
14     
15     printf("a = %d\n", a);  // a = 5;
16     printf("b = %d\n", b);  // b = 5;
17 }
18 
19 void demo()
20 {
21     printf("demo:\n");
22     
23     const int& c = 1;  // 只读变量;
24     int* p = (int*)&c;
25     
26     //c = 5;  // error: assignment(赋值) of read-only reference 'b';
27     
28     *p = 5;
29     
30     printf("c = %d\n", c);  // c = 5;
31 }
32 
33 int main(int argc, char *argv[])
34 {
35     example();
36     
37     printf("\n");
38     
39     demo();
40 
41     return 0;
42 }

    2,结论:

  1,要使一个已经存在的变量拥有只读属性,变成只读变量,定义一个        const 引用即可;

 

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

    1,代码示例:

1 struct tref
2 {
3     char& r;
4 };
5 
6 printf("sizeof(tref) = %d\n", sizeof(tref));

   

6,引用的思考编程实验:

    1,main.cpp 文件:

 1 #include <stdio.h>
 2 
 3 struct tref
 4 {
 5     char& r;  // 定义引用 r;
 6 };
 7 
 8 int main(int argc, char *argv[])
 9 { 
10     char c = 'c';
11     char& rc = c;
12     tref ref = { c };  // r 引用 c;
13     
14     printf("sizeof(char&) = %d\n", sizeof(char&));  // 1;这里求对应的变量大小;
15     printf("sizeof(rc) = %d\n", sizeof(rc));  // sizeof(rc) => 1;
16     
17     printf("sizeof(tref) = %d\n", sizeof(tref));  // 4;
18     printf("sizeof(ref.r) = %d\n", sizeof(ref.r));  // sizeof(c) => 1;
19 
20     return 0;
21 }

   

7,引用在 c++ 中的内部实现是一个指针常量:

    1,type& name <==> type* const name;

    2,void f(int& a)                       void f(int* const a)

         {                                          {

            a = 5;               <==>               *a = 5;  // 内部实现是这样;

         }                                         }

    3,c++ 编译器在编译过程中用指针常量作为引用的内部实现,因此引用所占用     的空间大小与指针相同;

    4,从使用的角度,引用只是一个别名,c++ 为了实用性而隐藏了引用的存储空     间这一细节;

   

8,引用的存储空间:

    1,main.cpp 文件:

 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\n", sizeof(r));  // 12;
19     printf("sizeof(r.before) = %d\n", sizeof(r.before));  // 4;
20     printf("sizeof(r.after) = %d\n", sizeof(r.after));  // 4;
21     printf("&r.before = %p\n", &r.before);  // 0xbf8a300c;
22     printf("&r.after = %p\n", &r.after);  // 0xbf8a3014;
23 
24     return 0;
25 }

   

9,c++ 中的引用旨在大多数情况下代替指针:

    1,功能性:可以满足多数需要使用指针的场合;

    2,安全性:可以避开由于指针操作不当而带来的内存错误;

    3,操作性:简单易用,又不失功能强大;

   

10,函数返回引用实例分析:

    1,main.cpp 文件:

 1 #include <stdio.h>
 2 
 3 int& demo()  // int* const demo()
 4 {
 5     int d = 0; // warning: reference to local variable 'd' returned;
 6     
 7     printf("demo: d = %d\n", d);  // d = 0;
 8     
 9     return d;  // return &d;,返回局部变量地址是不可以的;
10 }
11 
12 int& func()
13 {
14     static int s = 0;
15     
16     printf("func: s = %d\n", s);  // s = 0;
17     
18     return s;//这里是可以的;return &s;,地址不会因为函数返回而被摧毁;
19 }
20 
21 int main(int argc, char* argv[])
22 {
23     int& rd = demo();
24     int& rs = func();
25     
26     printf("\n");
27     printf("main: rd = %d\n", rd);  rd = 13209588;
28     printf("main: rs = %d\n", rs);  rs = 0;
29     printf("\n");
30     
31     rd = 10;  // 对栈上已经释放的四个字节进行操作赋值,没意义;
32     rs = 11;
33     
34     demo();  // d = 0; 每次调用都会被重建;
35     func();  // s = 11;
36     
37     printf("\n");
38     printf("main: rd = %d\n", rd);  // rd = 13209588;
39     printf("main: rs = %d\n", rs);  // rs = 11;
40     printf("\n");
41     
42     return 0;
43 }

   1,引用能在最大程度上避开内存操作错误,但是不能够寄希望于完全避    免,因为它本质是指针;

   

11,小结:

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

    2,const 引用可以使得变量只有只读属性;

       1,可以避开误对变量赋值;

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

    4,引用的最终本质为指针;

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