计算机

常量

常量 (constant) 在程序中不能改变其值,其定义时有 const 声明符。

C++ 中的常量并不要求在编译时就可以确定其值。对于那些编译器不能确定的“常量”,更恰当地说应该理解为只读(read-only)量。对于真正的常量,推荐使用 constexpr(常量表达式)来指定。

定义原则:从右往左读

const 对象

初始化

常量必须有初始化,但其初始化可以是多样的,可以用字面值常量、其他变量甚至任意复杂的表达式来初始化:

const int a = 10;

int b;
std::cin >> b;
const int c = b; // c 的值初始化为 b 当前的值

std::string s;
std::cin >> s;
const int d = s.length();

以上的定义中,其实只有 a 可以在编译期确定,是真正的“常量”,而 b, s 都只是初始化后不能修改的量,本质上是只读量。

常量引用

对常量的引用(reference to const),简称常量引用,使用 const int & 定义(以 int 引用为例)。

const int a = 100;
const int &r = a;

不能使用非常量的引用来引用一个常量:

const int a = 1000;
int &r1 = a; // 错误

对变量的常量引用

常量引用虽然是对 const 的引用,但可以引用一个变量,此时常量引用不能改变该变量的值,但变量本身可以通过其他途径修改。

C++ Primer:对常量的引用,只是引用自己以为指向的是常量,它们自己自觉地不去修改引用的量,而不代表引用的真的是常量。

例如

int a = 100;
const int &r = a;
std::cout << "r = " << r << std::endl; // r = 100
a = 200;
std::cout << "r = " << r << std::endl; // r = 200
// r = 300; // 错误:r 是常量引用,不能通过 r 修改 a 的值

对变量的常量引用更多见于函数的形参。

临时量

以 const int & 为例,使用常量引用时,指向的对象可以不是 int 或 const int 。此时,编译器将自动创建临时量 (temporary)。例如,当指向字面值常量、double 变量、表达式时,编译器将创建临时量。

例如,int &r 指向 double 型变量 pi 时,等价于如下语句:

const int tmp = pi; // 创建临时量
const int &r = tmp;

以下 r2, r3 和 r4 都会创建临时量。

int i = 100;
const int &r1 = i;
const int &r2 = 21; // 字面量常量的引用
double x = 12.5;
const int &r3 = x;
const int &r4 = 2 * r1;
std::cout << "r2 = " << r2 << ", r3 = " << r3 << ", r4 = " << r4 << std::endl;
x = 14.8;
std::cout << "r3 = " << r3 << std::endl; // 这时候 x 改变了,r3 不会一起修改
i = 300;
std::cout << "r1 = " << r1 << ", r4 = " << r4 << std::endl; // i 和 r1 改变了,r4 不变

常量指针

对常量的指针(pointer to const)简称常量指针,指的是不能修改所指值的指针,使用 const int * 定义(以 int 指针为例)。类似于常量引用,常量指针同样不要求被指向的是常量。

C++ Primer:对常量的指针,只是指针自己以为指向的是常量,它们自己自觉地不去修改指向的量,而不代表指向的真的是常量。

但不同于对引用的常量,对指针的常量不能指向类型不一致的变量:

double pi = 3.14;
// const int *p2 = &pi; // 常量 int 指针无法指向 double
const int *p2 = (int*) &pi; // 强制类型转换
std::cout << "*p2 = " << *p2 << std::endl; // double 处的值被重新解释为一个 int

指针常量(常指针)

指针常量(也称为常指针,const pointer)指的是不能指向其他值(不能修改指向的地址)的指针。这说明指针本身是个常量(所以叫 constant pointer),这种指针可以修改指向的值。

为了与普通的指针区别开,一般普通的指针称为指针变量。

定义指针常量时,const 放在 * 之后:

int a = 1, b = 2;
int *const p = &a; // 指针常量
*p = 3; // 可以修改所指值
// p = &b; // 不能指向其他量

常量指针常量

指针常量和常量指针的结合,以 int 为例,使用 const int *const 定义。

int a = 1;
const int *const p = &a;

顶层 const 与底层 const

当对象本身不可以修改时,称为顶层 const(top-level const),const int 和 int *const 都是顶层 const。

而当所指对象不可以修改时,称为底层 const(low-level const),对常量的引用、对常量的指针都是底层 const。

指针和引用指向一个量时,其底层 const 必须传递。例如,不能用普通的引用来指向一个常量:

const int c = 1;
int* p = &c; // 错误
BEYOND THE ARTICLE

读完了,有什么想法?

阅读已保存的问答示例,并循着引用回到原文。

查看公开问答示例
— 本文完 — 返回文章列表