发布于2026-07-01 阅读(0)
扫一扫,手机访问
const 大概是 C++ 初学者最早接触的关键字之一,但你很快会发现,它绝不仅仅意味着“一个不可修改的常量”。随着学习的深入,它在类型安全、编译器优化、接口设计乃至多线程编程中都扮演着重要角色。

最简单的用法当然是从定义一个常量开始,让变量的值变得不可修改。
const int MAX_SIZE = 100; // MAX_SIZE = 200; // 错误!不能修改 int const MAX_SIZE_2 = 100; // 与上一行完全等价,const 在类型前后均可
有两个要点需要特别注意:
const 修饰的变量必须初始化,否则之后也没机会赋值了。const int 和 int const 在写法上是等价的,但为了风格统一,通常把 const 写在最前面。在 C++ 中,用 const 或 constexpr 代替 #define 来定义常量是更推荐的做法。这样做的好处在于有类型检查,并且严格遵循作用域规则,不会像宏定义那样带来意外的文本替换问题。
最让人头疼的,大概就是 const 在指针里的用法——当然,也是面试官最喜欢挖坑的地方。核心规则其实很简单:看 const 在 * 的哪一边。
int value = 10; const int* ptr = &value; // 等同于 int const* ptr
ptr 修改其所指对象的值(例如 *ptr = 20 是非法的)。ptr 自身可以指向别的对象。另外,如果 value 本身不是 const,你仍然可以通过 value 直接修改它。int value = 10; int* const ptr = &value;
ptr 本身的值(即指向的地址)不可变,一旦初始化就不能再指向别处。*ptr 修改所指对象的值。const int value = 10; const int* const ptr = &value;
这里有个小窍门:以 * 为界,const 在左边时,修饰的是指向的对象;在右边时,修饰的是指针本身。所以 const int * 修饰的是 int,而 int * const 修饰的是指针。
这个概念虽然在基础阶段不常提,但在泛型编程和类型推导中却非常重要。
int *const p1,这里的 p1 就是顶层 const。const int *p2,这里的 *p2 是底层 const。关键区别在于拷贝时的行为:
const 在函数中的应用,是写出健壮接口的关键。
先看形参。这和普通变量一样,如果你确定函数内部不会修改它,那就加上 const,既安全,也能让调用方放心。但要注意,在函数声明中,顶层 const 会被忽略:比如 void func(int val) 和 void func(const int val) 其实是同一个声明。
而指针和引用参数的情况就不同了。底层 const 在这里有实质区别,能决定函数可以接受什么类型的实参。使用 const & 作为参数是避免拷贝、同时保护原数据的最佳实践。
返回一个 const 值类型,比如 const int func(),其实没啥实际意义,因为调用者拷贝后本来就可以随便改。但返回 const 引用时,意义就重大了——它可以防止调用者通过返回值修改内部数据,同时避免了不必要的拷贝。
要说 const 在类设计里最精髓的地方,那一定是 const 成员函数。它的语法很简单:在成员函数参数列表后加 const 关键字即可。
它的实际作用,体现在三个方面:
this 指针的类型是 const Widget* const,无法修改非 mutable 成员。const 来提供不同的实现,const 对象走 const 版本,非 const 对象走普通版本。你可能会问:如果某个 const 成员函数确实需要修改某个变量呢?比如缓存数据、互斥锁这些与逻辑状态无关的内部机制。这时候就该 mutable 出场了。把这类变量声明为 mutable,就能在 const 函数中安全地修改它们了。
STL 的迭代器和指针差不多,也有 const 之分。
const iterator:迭代器本身是 const,不能指向别处,但可以修改其指向的元素。const_iterator:指向的元素是 const,不能通过它修改元素,但迭代器本身可以移动。换句话说,前者是 T* const,后者是 const T*。当遍历一个容器且不需要修改元素时,优先使用 cbegin() 和 cend(),它们不管容器本身是不是 const,都返回 const_iterator,更加安全。
说到底,const 是 C++ 类型系统中一位“守夜人”:
const & 传参防止拷贝和修改;const 返回值保护内部数据。const 成员函数是可被常量对象调用的安全接口,mutable 则处理物理常量性与逻辑常量性的分离。掌握 const,不仅仅是记住语法,更重要的是形成一种习惯——用 const 告诉编译器你的不变性约束。只有这样,才能写出更安全、更清晰的 C++ 代码。
答案要点:必须初始化。因为 const 对象一旦创建,其值就不能再改变,若不初始化,它将永远拥有一个不确定的值。
答案要点:没有区别,完全等价。当 const 修饰的是基本类型且没有指针参与时,位置不影响含义。
答案要点:
const 有类型检查,#define 只是文本替换。const 遵循作用域规则,#define 从定义处到文件结束(或 #undef)。const 可以被调试器看到,#define 宏名在编译预处理后就被替换了。const 或 constexpr。答案要点:
const int *p:指向常量的指针,不能通过 *p 修改所指对象,但 p 可以指向别处。int *const p:常量指针,p 本身不可变(不能指向别处),但可以通过 *p 修改所指对象。int a = 10; const int *p = &a; int *q = p; // 这行有什么问题?
答案要点:错误,p 是底层 const,q 是普通指针。如果把 p 赋给 q,就可以通过 *q 修改一个 const int 指向的对象,破坏了常量性。需要改为 const int *q = p; 或强制类型转换(不推荐)。
const int a = 10; int *p = (int*)&a; *p = 20;
答案要点:代码可能编译通过,但行为是未定义的。a 本身是 const 对象,可能被放在只读内存区,强制修改会导致运行时崩溃或奇怪的优化行为。不要这样做。
答案要点:
const int a 中的 a,或 int *const p 中的 p)。const int *p 中的 *p,或 const int &r 中的引用对象)。int i = 0; const int ci = i; const int *p1 = &ci; int *const p2 = &i; p1 = p2; // (1) p2 = p1; // (2) const int *const p3 = p2; // (3)
答案要点:
p2 是顶层 const,赋值给 p1(底层 const)没问题,p1 的底层 const 保持不变。p2 是顶层 const 指针,本身不能被赋值。p2 的底层是 non-const,赋给 const int 是安全的。void f(int); void f(const int);
答案要点:不构成重载,这是重复声明。顶层 const 在函数参数中被忽略,编译时会报重复定义。因为它们接受的实参类型没有区别。
void f1(int&); void f2(const int&);
答案要点:
f1 只能接受非 const 的左值,不能接受 const 对象或右值(字面量、临时对象等)。f2 可以接受任何 int 类型的实参:非 const 左值、const 左值、右值。const & 是一个通用的只读引用。答案要点:
答案要点:
const 修饰,承诺该函数不会修改对象的状态。答案要点:
mutable 修饰的成员变量,即使在 const 成员函数中也可以被修改。class A {
public:
void show() { cout << "non-const" << endl; }
void show() const { cout << "const" << endl; }
};
int main() {
A a;
const A ca;
a.show();
ca.show();
return 0;
}
答案要点:输出 non-const 和 const。const 对象调用 const 版本,非 const 对象优先调用非 const 版本。
答案要点:const 类名* const。即指向常量对象的常量指针,因此不能通过 this 修改成员变量(mutable 除外)。
答案要点:
iterator:可读写所指元素。const_iterator:只能读,不能修改元素(*it 返回 const 引用)。类似于 const T*。const iterator(迭代器本身是常量),类似于 T* const,实际使用较少。答案要点:无论容器本身是否为 const,都返回 const_iterator,便于编写只读遍历代码,增强安全性。
这些题目覆盖了 const 在面试中从基础到进阶的核心考察点,如果能全部清晰回答,const 这块基本就算过关了。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8