当const, reference, pointer相遇

时间:2021-08-20 05:28:33

C语言的初学者可能会对,常量指针、指向常量的指针、常量指向常量的指针迷糊一阵。但毕竟也就那么几种情况,熟悉了之后就可以理解了。C++中又多了一个叫做引用的东西,其实这几个东西各自使用也挺简单的,但是如果组合到一起那真叫一个奇葩!相信很有经验的C++程序员也会迷糊一阵!下面我们就说说这个奇葩的东西!

 

情况1: const + pointer

这个就是我们开头说的C中也存在的奇葩组合。看代码先

    int       val  = 10;
    const int cval = 11;

    int *ptr;
    ptr = &val;                 // PASS,   将指向no const的指针指向no const变量
    ptr = &cval;                // Failed, 将指向no const的指针指向const变量

 const int * cptr1;          // PASS,   const作用于pointer指向的类型,指针本身不是const, 可以以后初始化
    cptr1 = &val;               // PASS,   将指向const的指针指向no const变量
    cptr1 = &cval;              // PASS,   将指向const的指针指向const变量

    int *const cptr2;           // Failed, const作用于指针, const类型变量必须给初值!
    int *const cptr2 = &val;    // PASS,   将指向no const的const指针指向的no const变量
    int *const cptr2 = &cval;   // Failed, 将指向no const的const指针指向的const变量

    const int *const cptr2;     // Failed, 第二个const作用于指针, const类型变量必须给初值!
    const int *const cptr2 = &val;    // PASS, 将指向const的const指针指向的no const变量
    const int *const cptr2 = &cval;   // PASS, 将指向const的const指针指向的const变量

其实写的很清楚了,最主要的是要弄清楚两件事情:

第一,在指针类型中有const出现的时候,要弄清楚const修饰的是指针本身还是指针指向的类型。

第二,遵循“权限缩小原则”,在值传递的过程中权限可以不变,也可以变小,但是不能变大。也就是说no const的值可以赋给const变量,但是不能把const值赋值给no const变量。这个理论同样适于其他限定符。

 

情况2: const + reference

这个组合就是C++中独有的了,看代码先

    int       val  = 10;
    const int cval = 11;

    int &ref1 = val;     // PASS,   no const引用关联no const变量
    int &ref1 = cval;    // Failed, no const引用关联const变量
    int &ref1 = val + 1; // Failed, no const引用关联临时变量
    double &ref1 = val;  // Failed, no const引用关联临时变量(类型转换产生临时变量)

    const int &ref2 = val;     // PASS,  const引用关联no const变量
    const int &ref2 = cval;    // PASS,  const引用关联const变量
    const int &ref2 = val + 1; // PASS,  const引用关联临时变量
    const double &ref2 = val;  // PASS,  const引用关联临时变量(类型转换产生临时变量)

同样注意两件事儿:

第一, 遵循“权限缩小原则”。可以由no const向const转移,但是不能反过来。

第二, 在有reference存在的时候一定要注意临时变量的问题。C++规定只有const引用才能关联临时变量,非const引用关联临时变量时非法的。除了上面列出的两种产生临时变量的情况之外,在函数返回的时候还可以产生临时变量。但是,坑爹的是VC2010中非const引用也可以关联由一个函数返回产生的临时变量,它竟然不报错!可能是VS做了某种优化吧?在g++中可以正常报出来。临时变量的问题也是个话题,改次再详细说。

 

情况3: pointer + reference 和 const + pointer + reference

本来打算分开写的,但是发现他们的耦合度太高了,还是写到一块儿吧。先看代码:

{
        int       val  = 10;
        const int cval = 11;
        int       *ptr   = &val;
        const int *cptr1 = &cval;
        int * const cptr2       = &val;
        const int * const cptr3 = &cval;

        int * &ref1 = ptr;           // OK, no const引用关联no const指针对象ptr
        int * &ref2 = cptr1;         // Failed, no const引用关联指向const的指针对象
        int * &ref3 = &val;          // Failed, no const引用关联临时变量(&val是临时变量哦!)
        int * &ref4 = cptr2;         // Failed, no const引用关联const指针对象

        int * const &cref1 = ptr;    // OK, const引用关联非const指针对象(const作用于引用)
        int * const &cref2 = cptr1;  // Failed, const引用(指向no const的指针)关联指向const对象的no const指针
        int * const &cref3 = cptr2;  // OK, const引用(指向no const的指针)关联const指针对象
        int * const &cref4 = &val;   // OK, const引用关联临时对象(指向no const的指针临时变量)
        int * const &cref5 = &cval;  // Failed, const引用关联临时对象(指向no const的指针临时变量)

        const int * &cref6 = ptr;    // OK, const作用于引用所关联的类型,要求是指向const的指针。向下可以兼容指向非const的指针
        const int * &cref7 = cptr1;  // OK, 准确匹配
        const int * &cref8 = cptr2;  // Failed, 所关联类型指针是const指针
        const int * &cref9 = &cval;  // Failed, 类型准确匹配,但是尝试关联的是一个临时对象。

        const int * const &ccref = ptr;   // OK, 双const指针引用通吃所有的
        const int * const &ccref = cptr1; // OK, 双const指针引用通吃所有的
        const int * const &ccref = cptr2; // OK, 双const指针引用通吃所有的
        const int * const &ccref = cptr3; // OK, 双const指针引用通吃所有的
        const int * const &ccref = &val;  // OK, 双const指针引用通吃所有的
        const int * const &ccref = &cval; // OK, 双const指针引用通吃所有的
    }

总结:

原理其实不难遵循几个关键点就可以了。

1. 确定const的作用对象,引用还是指针指向的类型。

2. 注意临时变量的问题,只有const引用才能关联临时变量的!

3. 记住一个值,作用在它上面的限制可以越来越多,但是不能变少!

 

关于临时变量的问题,是个big problem,改次再说,而且在C++0x里面加入了右值引用,这个貌似就是专门为临时变量所加入的类型。下次也深入研究一下。Over!