常值
C++ 定义了一套完善的只读量定义方法,被常量修饰符 const
修饰的对象或类型都是只读量,只读量的内存存储与一般变量没有任何区别,但是编译器会在编译期进行冲突检查,避免对只读量的修改。因此合理使用 const
修饰符可以增加代码健壮性。
常类型¶
在类型的名字前增加 const 修饰会将该类型的变量标记为不可变的。具体使用情况有常量和常引用(指针)两种。
常量¶
这里的常量即常变量,指的是 const 类型的变量(而不是标题里泛指的只读量)。常类型量在声明之后便不可重新赋值,也不可访问其可变成员,只能访问其常成员。常成员的定义见后文。
类型限定符
C++ 中类型限定符一共有三种:常量(const)、可变(mutable)和易变(volatile),其中默认情况下是可变变量,声明易变变量的情形是为了刻意避免编译器优化。
1 2 3 | const int a = 0; // a 的类型为 const int
// a = 1; // 报错,不能修改常量
|
常引用、常指针¶
常引用和常指针也与常量类似,但区别在于他们是限制了访问,而没有更改原变量的类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | int a = 0;
const int b = 0;
int *p1 = &a;
*p1 = 1;
const int *p2 = &a;
// *p2 = 2; // 报错,不能通过常指针修改变量
// int *p3 = &b; // 报错,不能用普通指针指向 const 变量
const int *p4 = &b;
int &r1 = a;
r1 = 1;
const int &r2 = a;
// r2 = 2; // 报错,不能通过常引用修改变量
// int &p3 = b; // 报错,不能用普通引用指向 const 变量
const int &r4 = b;
|
另外需要区分开的是“常类型指针”和“常指针变量”(即常指针、指针常量),例如下列声明
1 2 3 4 5 6 7 8 9 | int* const p1; // 类型为int的常指针,需要初始化
const int* p2; // 类型为const int的指针
const int* const p3; // 类型为const int的常指针
int (*f1)(int); // 普通的函数指针
// int (const *f2)(int); // 指向常函数的指针,不可行
int (*const f3)(int) = some_func; // 指向函数的常指针,需要初始化
int const* (*f4)(int); // 指向返回常指针的函数指针
int const* (*const f5)(int) = some_func; // 指向返回常指针的函数的常指针
|
我们把常类型指针又称 底层指针、常指针变量又称 顶层指针。
另外,C++ 中还提供了 const_cast
运算符来强行去掉或者增加引用或指针类型的 const 限定,不到万不得已的时候请不要使用这个关键字。
常参数¶
在函数参数里限定参数为常类型可以避免在函数里意外修改参数,该方法通常用于引用参数。此外,在类型参数中添加 const 修饰符还能增加代码可读性,能区分输入和输出参数。
1 2 3 4 | void sum(const std::vector<int> &data, int &total) {
for (auto iter = data.begin(); iter != data.end(); ++iter)
total += *iter; // iter 是 const 迭代器,解引用后的类型是 const int
}
|
常成员¶
常成员指的是类型中被 const 修饰的成员,常成员可以用来限制对常对象的修改。其中,常成员变量与常量声明相同,而常成员函数声明方法为在成员函数声明的 末尾(参数列表的右括号的右边)添加 const 修饰符。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | // 常成员的例子
struct X {
X();
const int* p; // 类型为 int* 的常成员
int* const q; // 类型为 const int* 的可变成员
const int r() const;
// 第一个 const 修饰返回值,而最后的 const 修饰的是这个成员函数。
};
X a;
*(a.p)++; // 可行
// *(a.q)++; // 报错,不可修改 const int 类型变量
// 常成员函数的例子
const std::vector<int> c{1, 2};
// c.push_back(3); // 报错,不可访问常量的可变成员
// vector::push_back() 不是常成员
int s = c.size(); // vector::size() 是常成员,可以访问
|
常表达式 constexpr(C++11)¶
constexpr 说明符的作用是声明可以在编译时求得函数或变量的值,它的行为和 C 语言中的 const 关键字是一致的,会将变量结果直接编译到栈空间中。constexpr 还可以用来替换宏定义的常量,规避 宏定义的风险。constexpr 修饰的是变量和函数,而 const 修饰的是类型。
实际上把 const 理解成 "readonly",而把 constexpr 理解成 "const" 更加直观。
1 2 3 4 5 6 7 8 | constexpr int a = 10; // 直接定义常量
constexpr int FivePlus(int x) { return 5 + x; }
void test(const int x) {
std::array<x> c1; // 错误,x在编译期不可知
std::array<FivePlus(6)> c2; // 可行,FivePlus编译期可以推断
}
|
参考资料¶
build本页面最近更新:,更新历史
edit发现错误?想一起完善? 在 GitHub 上编辑此页!
people本页面贡献者:OI-wiki
copyright本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用