码迷,mamicode.com
首页 > 其他好文 > 详细

引用和指针(十)

时间:2018-05-07 16:44:50      阅读:164      评论:0      收藏:0      [点我收藏+]

标签:C++   指针   引用   

        前面我们讲了引用,这节我们就来看看引用和指针有何区别?又有何相同点。首先我们来看看在 C++ 中,const 什么时候为只读变量?什么时候是常量呢?

        关于 const 常量的判别准则有这么几个:1、只有用字面量初始化的 const 常量才会进入符号表;2、使用其它变量初始化的 const 常量仍然是只读变量;3、被 volatile 修饰的 const 常量不会进入符号表。凡是在编译期间不能直接确定初始值的 const 标识符,都被作为只读变量处理。const 引用的类型与初始化变量的类型相同时,初始化变量成为只读变量不同时,生成一个新的只读变量

        下来我们以代码为例进行分析

#include <stdio.h>

int main()
{
    const int x = 1;
    const int& rx = x;
    
    int& nrx = const_cast<int&>(rx);
    
    nrx = 5;
    
    printf("x = %d\n", x);        // 1
    printf("nx = %d\n", rx);      // 5
    printf("nrx = %d\n", nrx);    // 5
    
    printf("&x = %p\n", &x);
    printf("&nx = %p\n", &rx);
    printf("&nrx = %p\n", &nrx);
    
    volatile const int y = 2;
    int*p = const_cast<int*>(&y);
    
    *p = 6;
    
    printf("y = %d\n", y);        // 6
    printf("p = %p\n", p);
    
    const int z = y;
    
    *p = 7;
    
    printf("z = %d\n", z);        // 6
    printf("p = %p\n", p);
    
    char c = 'c';
    char& rc = c;
    const int& trc = c;
    
    rc = 'a';
    
    printf("c = %c\n", c);        // a
    printf("rc = %c\n", rc);      // a
    printf("trc = %c\n", trc);    // c
    
    return 0;
}

        我们来分析下这个程序,在第 5 行定义了一个 const 修饰的 x,所以 x 会进入符号表,它为常量,但是编译器仍然会在栈上为它分配 4 字节的空间。第 6 行是 const 修饰的引用,所以 rx 只是一个具有只读属性的变量,通过第 8 行的 const_cast 去除 rx 的只读属性,在第 10 行改变了 nrx 的值,所以第 12 - 14 行应该打印出 1, 5, 5。第 16 - 18 行打印出的三个地址值应该是相同的,因为它们都是引用。第 20 行定义的由 volatile const 修饰的变量 y 在本质上也是一个具有只读属性的变量,所以通过第 21 行的 const_cast 会去掉它的只读属性,通过第 23 行的指针操作,会改变它的值。所以第 25 行应该打印出 6。第 28 行定义的 const int z,由于它指向的 y 是被 volatile 修饰的,所以在读取 z 的值时会去 y 的地址空间里读取,通过第 30 指针操作并不会改变它的值,第 32 行应该打印出 6。在第 36 行通过 rc 引用了 c,所以他俩是同一个东西。因为第 37 行的引用是不同类型间的引用,所以它会始终指向的是 c 第一次定义的值。我们通过第 39 行的指针操作,会改变 c 和 rc 的值,但并不会改变 trc 的值。我们来看看编译结果

技术分享图片

        我们看到编译的结果和我们所分析的是一致的,证明我们的分析是正确的。

        下来我们来看看引用和指针的关系,为何理解我们之前所说的“引用的本质就是指针常量”。1、指针是一个变量:a> 值为一个内存地址,不需要初始化,可以保存不同的地址;b> 通过指针可访问对应内存地址中的值;c> 指针可以被 const 修饰成为常量或者只读变量;2、而引用只是一个变量的名字:a> 对引用的操作(赋值,取地址等)都会传递到代表的变量上;b> const 引用使其代表的变量具有只读属性;c> 引用必须在定义时初始化,之后无法代表其它变量

        从使用 C++ 语言的角度来看:a> 引用于指针没有任何的关系。b> 引用是变量的新名字。 c> 操作引用就是操作对应的变量;从 C++ 编译器的角度来看:a> 为了支持新概念“引用 ”必须要一个有效的解决方案。 b> 在编译器内部,使用指针常量来实现“引用”。 c> 因此,“引用”在定义时必须初始化。

        在工程项目开发中:当进行 C++ 编程时,直接站在使用的角度看待引用,与指针毫无关系,引用就是变量的别名;当对 C++ 代码进行调试分析时,一些特殊情况,可以考虑站在 C++ 编译器的角度看待引用。

        下来我们以代码为例进行分析

#include <stdio.h>

int a = 1;

struct SV
{
    int& x;
    int& y;
    int& z;
};

int main()
{
    int b = 2;
    int* pc = new int(3);
    SV sv = {a, b, *pc};
    //int& array[] = {a, b, *pc};
    
    printf("sv.x = %d\n", sv.x);
    printf("sv.y = %d\n", sv.y);
    printf("sv.z = %d\n", sv.z);
    
    printf("&sv.x = %d\n", &sv.x);
    printf("&sv.y = %d\n", &sv.y);
    printf("&sv.z = %d\n", &sv.z);
    
    delete pc;
    
    return 0;
}

        我们在里面定义了一个结构体引用。在第 16 行赋值 a, b, *pc。那么我们打印的结构体里的值就应该为 1,2,3。我们来看看编译结果,看看这样的引用是否被支持

技术分享图片

        我们再来用引用初始化数组看看是否被支持呢?去掉第 17 行的注释

技术分享图片

        我们看到它报错了,那么为什么它支持结构体的引用,却不支持数组的引用呢?别忘了它是要兼容 C 语言的特性,在 C 语言中,数组间的每个元素都是连续的,相邻元素的地址差值应该为 4,可是我们的引用的是不同地址处的元素,当然不符合这个性质了。所以在 C++ 中,引用除了数组,其他的都支持。通过对指针和引用的学习,总结如下:1、指针是一个变量,引用只是一个变量的新名字;2、const 引用能够生成新的只读变量;3、在编译器内部使用指针常量实现“引用”;4、编译时不能直接确定初始值的 const 标识符都是只读变量。


        欢迎大家一起来学习 C++ 语言,可以加我QQ:243343083

引用和指针(十)

标签:C++   指针   引用   

原文地址:http://blog.51cto.com/12810168/2113575

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!