const 关键字在 C++ 中有哪些作用?
const 是 C++ 中非常重要且常用的关键字,它的核心语义是“只读”(不可修改)。合理使用 const 可以提高代码的安全性、可读性,并能帮助编译器进行优化。
在 C++ 中,const 的作用非常广泛,主要可以归纳为以下几个方面:
1. 修饰基本变量
最基础的用法,声明一个常量。变量一旦被初始化,其值就不能再被改变。
注意: const 变量必须在声明时初始化。
cpp
const int a = 10;
// a = 20; // 错误!编译不通过,a 是只读的
2. 修饰指针(经典面试题)
const 与指针结合时,根据 const 的位置不同,作用也不同。通常可以用“就近原则”或“从右往左读”的方法来判断。
- 指向常量的指针 (Pointer to const):指针所指的数据不能修改,但指针本身的指向可以修改。cpp
int a = 10, b = 20; const int* p1 = &a; // 等价于 int const * p1 = &a; // *p1 = 30; // 错误:不能通过 p1 修改 a 的值 p1 = &b; // 正确:p1 可以指向别的地方 - 常量指针 (Const pointer):指针本身的指向不能修改,但所指的数据可以修改。cpp
int* const p2 = &a; *p2 = 30; // 正确:可以修改 a 的值 // p2 = &b; // 错误:p2 不能再指向 b - 指向常量的常量指针:指针的指向和所指的数据都不能修改。cpp
const int* const p3 = &a;
3. 修饰引用(最常用)
在 C++ 中,const 引用经常用于函数参数。
cpp
int a = 10;
const int& ref = a;
// ref = 20; // 错误:不能通过引用修改 a
4. 修饰函数参数
这是 const 最具实战价值的用法之一。
- 按值传递:通常不需要加
const,因为形参是实参的拷贝,修改形参不影响实参。 - 常量引用传递 (
const T&):极其重要。既能避免对象拷贝带来的性能开销,又能保证实参在函数内部不会被意外修改。cpp// 传递大型对象(如 string, vector 或自定义类)时,强烈建议使用 const 引用 void printString(const std::string& str) { // str += "a"; // 错误:保证了不会意外修改原字符串 std::cout << str << std::endl; }
5. 修饰函数返回值
- 返回 const 值:防止返回值被修改(通常用于返回指针或引用)。
- 返回 const 引用:常用于类的成员函数,返回类内部私有成员的引用,但不允许调用者修改它。cpp
class Person { std::string name; public: // 返回 const 引用,外界可以读取 name,但不能修改 const std::string& getName() const { return name; } };
6. 在面向对象(类)中的应用
- 修饰成员变量:
该成员变量在对象的生命周期内不可修改。必须在类的构造函数初始化列表中进行初始化。cppclass MyClass { const int id; public: MyClass(int i) : id(i) {} // 只能在这里初始化 }; - 修饰成员函数(常函数):
在函数声明末尾加const。它承诺该函数不会修改任何非静态成员变量。(注:如果确实需要在cppclass MyClass { int data; public: int getData() const { // data = 10; // 错误:const 成员函数不能修改普通成员变量 return data; } };const函数中修改某个成员变量,可以使用mutable关键字修饰该成员变量)。 - 修饰类对象(常对象):
const对象只能调用const成员函数。因为调用普通成员函数可能会修改对象状态,这与const对象的语义违背。cppconst MyClass obj(1); obj.getData(); // 正确:getData 是 const 函数
7. 替代宏定义 (#define)
在 C++ 中,强烈推荐使用 const 替代 #define 定义常量。
#define MAX_SIZE 100只是简单的文本替换,没有类型检查,且不受作用域限制。const int MAX_SIZE = 100;具有明确的类型,受编译器类型检查,且遵守作用域规则(如类作用域、命名空间作用域),方便调试。
总结:为什么要使用 const?
- 契约精神/安全性:明确告诉编译器和其他程序员,这个变量/对象是不应该被改变的。编译器会帮你检查,防止误操作(例如把
==误写成=)。 - 性能优化:使用
const引用传参可以避免不必要的对象拷贝;同时,编译器有时可以对const变量进行更好的寄存器优化。 - 接口设计规范:优秀的 C++ 代码中,只要是不修改对象状态的成员函数,或者不改变传入参数的函数,都应该加上
const(即“const 正确性” const correctness)。
右滑查看面试常问