【C++深度解析】9、const 常量?只读变量?

本文深入解析C++中const关键字的使用原则,区分只读变量与常量,介绍const引用的特性,以及如何在编程实践中正确应用const,确保代码的安全性和效率。


看了前面的关于 const 的内容,不知道是不是有疑问,const 什么时候为只读变量,什么时候是常量?

1 const 常量的判别准则

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

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

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

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

1.1 编程实验

// 9-1.c
#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);
    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 int y = 2;
    int* p = const_cast<int*>(&y);
    *p = 6;
    printf("y = %d\n", y);
    printf("p = %p\n", p);

    const int z = y;
    p = const_cast<int*>(&z);
    *p = 7;
    printf("z = %d\n", z);
    printf("p = %p\n", p);

    char c = 'c';
    char& rc = c;
    const int& trc = c;
    rc = 'a';
    printf("c = %c\n", c);
    printf("rc = %c\n", rc);
    printf("trc = %c\n", trc);
    return 0;
}
  • 程序第 5-8 行,x 通过字面量初始化,是常量,存储在符号表中;rx 通过变量 x 初始化,不能在编译器确定初始值,是只读变量;nrx 通过 const_cast 去掉了只读属性。修改nrx 修改的是内存的值,不能修改符号表中的值,所以 x 值不变,rx 和 nrx 值修改为 5。rx 是 x 的引用,nrx 是 rx 的引用,所以三者的地址是相同的。
  • 第 16-18 行,变量 y 被 volatile 修饰,是只读变量,指针 p 使用 const_cast 去除其只读属性,并指向变量 y,修改指针 p 指向的值也就是修改了内存,y 变为 6。
  • 第 22- 24 行,const 修饰的 z 通过变量 y 初始化,具有只读属性,指针 p 通过const_cast 去除其只读属性,并指向 z,修改 *p 也就是修改了内存值,所以 z 被修改为 7。
  • 第 28-30 行,trc 为 const int 型的引用,c 为 char 变量,类型不同,trc 生成一个新的只读变量,所以修改 rc 会 改变 c 的值,但是不影响 trc。

编译运行:

$ g++ 9-1.c -o 9-1
$ ./9-1
x = 1
rx = 5
nrx = 5
&x = 0x7ffee6ed4440
&rx = 0x7ffee6ed4440
&nrx = 0x7ffee6ed4440
y = 6
p = 0x7ffee6ed4444
z = 7
p = 0x7ffee6ed4448
c = a
rc = a
trc = c

当 const 修饰的变量是只读变量时,仅仅是说明不能通过这个只读变量修改内存的值,但是可以通过其他方法修改内存值。

2 小结

1、const 引用能够生成新的只读变量
2、编译时不能直接确定初始值的 const 标示符都是只读变量

在编程中,常量只读变量虽然都用于表示不可轻易更改的数据,但它们在语义、使用场景以及实现机制上存在显著差异。 常量通常在程序编译时就被确定下来,并且其值在整个程序生命周期内都是不可变的。这意味着常量的值在定义时就必须给出,并且不能被重新赋值。常量通常用于表示那些在程序运行期间不会改变的值,如数学常数(π)、物理常量(光速)等。在C#中,常量通过`const`关键字定义,例如`const double PI = 3.14159;`。一旦定义了这样的常量,尝试修改它的值会导致编译错误[^2]。 相比之下,只读变量(或称为只读字段)则提供了更多的灵活性。只读变量可以在构造函数中被初始化,这意味着它们的值可以在对象创建时根据不同的构造参数来设定。然而,一旦对象被创建,这些值就不能再被改变。这使得只读变量非常适合用来存储那些在对象生命周期内不会改变但又需要根据实例不同而有所区别的数据。在C#中,只读变量通过`readonly`关键字定义,例如在一个类中声明`public readonly int Number = 10;`。值得注意的是,尽管只读变量的值在对象创建后不能改变,但这并不意味着它们的值在编译时就已经确定[^2]。 从内存角度来看,在某些语言中,常量可能没有实际的内存地址,因为它们可能直接被编译器内联到使用它们的地方。而变量,包括只读变量,则总是拥有自己的内存位置。这一点在C++中尤为明显,其中常量可能不具备地址属性,而变量则肯定具有地址属性[^3]。 ### 示例代码 下面是一个简单的C#示例,展示了如何定义使用常量只读变量: ```csharp public class ExampleClass { public const double Pi = 3.14159; // 常量 public readonly int Id; // 只读变量 public ExampleClass(int id) { Id = id; // 只读变量在构造函数中初始化 } } ``` ### 相关问题 1. 在C#中,如何正确地定义使用只读变量? 2. 常量只读变量在程序性能上有何影响? 3. 如何选择使用常量还是只读变量? 4. 在哪些情况下更适合使用只读变量而不是常量? 5. 解释C++常量变量之间的地址属性差异。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值