const 变量

初始化与推断已经解决了“值从哪里来”。程序中的上限、比例和阈值通常是规则,而不是运行时随意修改的状态。把它们写成常量,可以让名字表达意图,也让编译器阻止误修改。本章把运行时固定的值写成 const 常量,编译期确定的规则值和头文件共享由下一章的 constexpr 承担。

固定运行时值

const 变量必须在创建时初始化,创建后不能再赋值:

片段:常量的初始化与赋值
// 片段
int current_value{12};
const int kMaxCount{5};

// kMaxCount = 6;  // 编译失败
current_value = 13; // 普通变量仍可修改

const 表示“不能通过这个名字修改”,不等于对象在所有路径上永远不可变。先问这个值是否代表规则或不应变化的事实,再决定是否使用它。运行时才知道的配置仍然适用:例如从配置文件读入之后不再修改的限值,写成 const 就能防止后续误改。

命名常量

完整示例输出两个常量的值:

const-variables.cpp
#include <iostream>

int main() {
  const int kMaxCount{5};
  const int kTimeoutMs{3000};

  std::cout << "最大数量: " << kMaxCount << "\n";
  std::cout << "超时毫秒数: " << kTimeoutMs << "\n";
  return 0;
}

项目约定常量使用 k 加大驼峰,例如 kMaxCount。名字应说明含义和单位:kTimeoutMs 的 Ms 表明单位是毫秒,使用者不必再查文档确认 3000 是秒还是毫秒。比例、时间等带单位的数值都适合把单位写进名字。

常见错误

只声明不初始化 const

const int limit; 没有可用的初始值,会编译失败,常量的值必须在创建时给出。

浮点用于精确比较

需要精确计数或比较时优先使用合适的整数单位,比例等测量值才考虑 double,并在数值安全章节学习容差比较。

自测问题

  1. 为什么 const 变量必须在创建时初始化?

    查看答案

    没有初始值就没有获得值的机会,之后也不能通过赋值补救,这样的变量没有可用状态,编译器直接拒绝。

  2. const 保证对象在所有路径上永远不可变吗?

    查看答案

    不保证。const 只约束“不能通过这个名字修改”,对象仍可能通过其他途径改变。先判断值是否代表规则,再决定是否使用。

  3. kTimeoutMs 比 kTimeout 好在哪里?

    查看答案

    单位写进了名字,使用者不必查文档确认 3000 的含义,也降低了把秒当毫秒使用的概率。

本章回顾

你已经能把不会改变的值写成有意义的 const 常量,并理解初始化要求。示例见 const-variables.cpp,下一章说明 constexpr 与多个 .cpp 共享的头文件常量。