关于 const 的疑问

const 什么时候为只读变量?什么时候为常量?

  • const 常量的判别标准

    • 只有用字面量初始化的 const 常量才会进入符号表
    • 使用其它变量初始化的 const 常量仍然只是只读变量
    • 被 volatile 修饰的 const 常量不会进入符号表

在编译期间不能直接确定初始值的 const 标识符,都被作为只读变量处理。

  • const 引用的类型与初始化变量的类型

    • 相同: 初始化变量为只读变量
    • 不同: 生成一个新的只读变量

编程实验: const 典型问题分析

#include <stdio.h>

/**
 * 使用常量初始化 const 引用,得到只读变量,进入符号表
 */
void code_1()
{
    const int x = 1;
    const int& rx = x;                // rx 只读变量
    
    int& nrx = const_cast<int&>(rx);
    
    nrx = 5;
    
    printf("x = %d\n", x);
    printf("rx = %d\n", rx);
    printf("nrx = %d\n", nrx);
    printf("&x = %p\n", &x);
    printf("&rx = %p\n", &rx);
    
    printf("&nrx = %p\n", &nrx);
}

/**
 * 被 volatile 修饰的 const 标识符仍为只读变量,不会进入符号表
 */
void code_2()
{
    volatile const int y = 2;         //  y为只读变量
    int* p = const_cast<int*>(&y);
    
    *p = 6;
    
    printf("y = %d\n", y);
    printf("p = %p\n", p);
}

/**
 * 使用变量初始化的 const 标识符仍为只读变量,不会进入符号表
 */
void code_3()
{
    int y = 0;
    const int z = y;                  // z 为只读变量
    int*p = const_cast<int*>(&z);
    
    *p = 7;
    
    printf("z = %d\n", z);
    printf("p = %p\n", p);
}

/**
 * const 引用的类型与初始化变量类型不同那个,得到一个新的只读变量
 */
void code_4()
{
    char c = 'c';
    char& rc = c;
    const int& trc = c;              // trc 为只读变量
    
    rc = 'a';
    
    printf("c = %c\n", c);
    printf("rc = %c\n", rc);
    printf("trc = %c\n", trc);
}

int main()
{
    code_1();
    printf("--------\n");
    code_2();
    printf("--------\n");
    code_3();
    printf("--------\n");
    code_4();
    
    return 0;
}
输出:
x = 1
rx = 5
nrx = 5
&x = 0xbfaf2cac
&rx = 0xbfaf2cac
&nrx = 0xbfaf2cac
--------
y = 6
p = 0xbfaf2cac
--------
z = 7
p = 0xbfaf2ca8
--------
c = a
rc = a
trc = c

关于引用的疑问

引用与指针有什么关系? 如何理解”引用的本质就是指针常量“?

  • 指针是一个变量

    • 值为一个内存地址
    • 通过指针可以访问对应内存中的值
    • 指针可以被 const 修饰成为常量或者只读变量
  • 引用只是一个变量的新名字

    • 对引用的操作(赋值,取地址等)都会传递到代表的变量上
    • const 引用使其代表的变量具有只读属性
    • 引用必须在定义时初始化,之后无法代表其它变量

  • 从使用 C++ 语言的角度来看

    • 引用与指针没有任何的关系
    • 引用是变量的新名字,操作引用就是操作对应的变量
  • 从 C++ 编译器的角度来看

    • 为了支持新概念 ”引用“ ,必须有一个有效的解决方案
    • 在编译器内部,使用指针常量来实现 ”引用“
    • 因此 ”引用“ 在定义时必须初始化

  • 在工程项目开发中

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

下面的代码有问题吗?

int a = 1;
int b = 2;
int* pc = new int(3);
int& array[] = {a, b, c};

编程实验: 引用典型问题分析

test_1.cpp

#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};

    printf("&sv.x = %p\n", &sv.x);
    printf("&sv.y = %p\n", &sv.y);
    printf("&sv.z = %p\n", &sv.z);
    
    delete pc;

    return 0;
}
输出:
&sv.x = 0x804a020
&sv.y = 0xbf91ef4c
&sv.z = 0x873d008

test_2.cpp

#include <stdio.h>

int a = 1;                    // 全局数据区

int main()
{
    int b = 2;               // 栈
    int* pc = new int(3);    // 堆
    int& array[] = {a, b, *pc};

    delete pc;

    return 0;
}
输出:
In function ‘int main()’:
error: declaration of ‘array’ as array of references

C++ 中为什么不支持引用数组呢?

C 数组是内存中的一块连续的存储空间,每个元素在内存顺序相邻存放,C++需要遵守并支持。当数组中的每个元素为引用即引用数组,破坏了这一特性。

小结

  • 指针是一个变量
  • 引用是一个变量的名字
  • const 引用能够生成的新只读变量
  • 在编译器内部使用指针常量实现 ”引用“
  • 编译时不能直接确定初始值的 const 标识符都是只读变量

以上内容参考狄泰软件学院系列课程,请大家保护原创!


TianSong
734 声望138 粉丝

阿里山神木的种子在3000年前已经埋下,今天不过是看到当年注定的结果,为了未来的自己,今天就埋下一颗好种子吧