C++ 中 const 关键字
2009-02-19
2024-07-23 补充C++11后的做法
在 C++ 中,const 是一个关键字(也称为保留字),它用于指定变量或对象的值在初始化后不能被修改。关键字是编程语言中具有特殊含义的词汇,编译器会识别这些词并对其进行特殊处理。
类型限定符(Type Qualifier)是指在编程语言中用来限定或修饰变量类型的关键字,它们提供额外的信息来约束变量的行为或存储方式。在 C++ 中,常见的类型限定符包括 const、volatile 和 mutable。
在这里主要说 const 。
const 是一个类型限定符,用于声明常量或只读数据。它表示一旦变量被初始化,其值不能被修改。const 关键字可以应用于变量、指针、引用、函数参数、返回值、成员函数和成员变量。用于声明常量或者指定某个变量、对象的成员、函数参数或返回值的某些方面是不可修改的。
使用 const
关键字编写高质量的代码。
常量声明(Constant Declaration)
用 const
定义常量以替代魔法数字(magic numbers),增加代码的可读性。
#include <iostream>
const int MAX_SIZE = 100;
int main() {
int arr[MAX_SIZE]; // 使用常量声明数组大小
std::cout << "Array size: " << MAX_SIZE << std::endl;
return 0;
}
常量声明是指用 const
关键字声明一个不可变的变量。
#include <iostream>
int main() {
const int constantValue = 42; // 声明一个常量变量
// constantValue = 10; // 错误:不能修改常量变量的值
std::cout << "constantValue: " << constantValue << std::endl;
return 0;
}
枚举类型的枚举值
枚举类型中的枚举值默认是整数类型,虽然不能直接指定为 const
,但它们在概念上是常量,不可修改。
enum Colors {
RED,
GREEN,
BLUE
};
int main() {
Colors color = RED;
// color = 10; // 错误:不能将整型赋值给枚举类型
return 0;
}
只读引用(Read-Only Reference)
使用 const
引用传递参数,避免拷贝,提高函数效率,并防止修改传入的参数。
示例1
#include <iostream>
void printVector(const std::vector<int>& vec) {
for (const int& elem : vec) {
std::cout << elem << " ";
}
std::cout << std::endl;
}
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
printVector(vec); // 通过只读引用传递vector
return 0;
}
示例2
#include <iostream>
// 使用常量引用作为函数参数
void printValue(const int& value) {
// value = 20; // 错误:不能修改通过常量引用传递的值
std::cout << "Value: " << value << std::endl;
}
int main() {
int x = 10;
printValue(x);
return 0;
}
函数参数(Function Parameters)
函数参数使用 const
修饰以防止函数内部修改传入的参数。
#include <iostream>
void processArray(const int* array, const int size) {
for (int i = 0; i < size; ++i) {
std::cout << array[i] << " ";
}
std::cout << std::endl;
}
int main() {
int arr[] = {1, 2, 3, 4, 5};
processArray(arr, 5); // 使用const指针传递数组
return 0;
}
返回值(Return Value)
使用 const
修饰返回值,确保返回的对象不能被修改,保护数据完整性。
#include <iostream>
const std::string& getGreeting() {
static const std::string greeting = "Hello, World!";
return greeting;
}
int main() {
const std::string& greet = getGreeting();
std::cout << greet << std::endl;
// greet = "Hi"; // 错误:不能修改const引用
return 0;
}
成员函数限定符(Member Function Qualifier)
类的成员函数使用 const
限定符,确保函数不会修改对象的状态。
#include <iostream>
class MyClass {
public:
MyClass(int value) : value_(value) {}
int getValue() const {
return value_;
}
void printValue() const {
std::cout << "Value: " << value_ << std::endl;
}
private:
int value_;
};
int main() {
MyClass obj(10);
obj.printValue(); // 调用const成员函数
return 0;
}
成员变量(Member Variable)
类的成员变量使用 const
修饰,确保其在初始化后不会被修改。
#include <iostream>
class MyClass {
public:
MyClass(int value) : value_(value) {}
int getValue() const {
return value_;
}
private:
const int value_; // const成员变量
};
int main() {
MyClass obj(10);
std::cout << "Value: " << obj.getValue() << std::endl;
return 0;
}
迭代器和指针(Iterators and Pointers)
使用 const
修饰迭代器和指针,确保它们指向的值不会被修改。
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 3, 4, 5};
std::vector<int>::const_iterator it;
for (it = vec.begin(); it != vec.end(); ++it) {
std::cout << *it << " ";
// *it = 10; // 错误:不能通过const迭代器修改值
}
std::cout << std::endl;
return 0;
}
常量指针
#include <iostream>
int main() {
int value = 10;
int otherValue = 20;
// 常量指针:指针本身是常量,不能指向其他地方
int* const ptr = &value;
*ptr = 30; // 可以修改指针指向的值
// ptr = &otherValue; // 错误:不能修改指针本身
// 指向常量的指针:不能通过指针修改指向的值
const int* ptrToConst = &value;
// *ptrToConst = 40; // 错误:不能修改指针指向的值
ptrToConst = &otherValue; // 可以改变指针本身
// 指向常量的常量指针:指针本身和指针指向的值都不能修改
const int* const constPtrToConst = &value;
// *constPtrToConst = 50; // 错误:不能修改指针指向的值
// constPtrToConst = &otherValue; // 错误:不能修改指针本身
std::cout << "value = " << value << std::endl;
return 0;
}
多态和虚函数(Polymorphism and Virtual Functions)
在多态和虚函数中使用 const
修饰,确保基类和派生类接口一致,并且保证对象状态不被修改。
#include <iostream>
class Base {
public:
virtual void show() const { // const虚函数
std::cout << "Base show" << std::endl;
}
};
class Derived : public Base {
public:
void show() const override { // 覆盖const虚函数
std::cout << "Derived show" << std::endl;
}
};
int main() {
Base* b = new Derived();
b->show(); // 调用派生类的const虚函数
delete b;
return 0;
}
函数返回类型后缀(Const After Function Return Type)
函数返回类型可以在函数名后面添加 const
,这种用法一般用于操作符重载,确保返回的对象不能被修改。
#include <iostream>
class MyClass {
public:
MyClass(int value) : value_(value) {}
// 返回一个常量对象
const MyClass& operator+(const MyClass& other) const {
static MyClass result(value_ + other.value_);
return result;
}
int getValue() const {
return value_;
}
private:
int value_;
};
int main() {
MyClass a(10);
MyClass b(20);
const MyClass& c = a + b; // 确保返回的对象不能被修改
std::cout << "Value of c: " << c.getValue() << std::endl;
// c.setValue(50); // 错误:不能修改常量对象
return 0;
}
constexpr 和 const
constexpr
是 C++11 引入的关键字,表示一个常量表达式。在 constexpr
中,const
是隐含的,因此 constexpr
对象也是常量。
#include <iostream>
constexpr int square(int x) {
return x * x;
}
int main() {
constexpr int result = square(10); // 在编译时计算结果
std::cout << "Square of 10 is " << result << std::endl;
return 0;
}
lambda 表达式捕获列表
在 lambda 表达式的捕获列表中,可以使用 const
来确保捕获的变量不会在 lambda 内部被修改。
#include <iostream>
int main() {
int value = 10;
auto lambda = [value]() mutable {
// value = 20; // 错误:不能修改捕获的常量
std::cout << "Captured value: " << value << std::endl;
};
lambda();
return 0;
}
引用成员变量中的 const
在类中,成员变量也可以是常量引用,这种情况一般用于引用另一个对象的常量属性。
#include <iostream>
class MyClass {
public:
MyClass(const int& ref) : ref_(ref) {}
int getValue() const {
return ref_;
}
private:
const int& ref_; // 常量引用成员变量
};
int main() {
int value = 42;
MyClass obj(value);
std::cout << "Value: " << obj.getValue() << std::endl;
return 0;
}
mutable 与 const 成员变量
mutable
关键字允许我们在 const
成员函数中修改特定的成员变量。
#include <iostream>
class MyClass {
public:
MyClass(int value) : value_(value), counter_(0) {}
int getValue() const {
++counter_; // 可以修改 mutable 成员变量
return value_;
}
int getCounter() const {
return counter_;
}
private:
int value_;
mutable int counter_; // mutable 成员变量
};
int main() {
MyClass obj(10);
std::cout << "Value: " << obj.getValue() << std::endl;
std::cout << "Counter: " << obj.getCounter() << std::endl;
return 0;
}
volatile 与 const
volatile
关键字表示一个变量可能在程序的控制之外被修改,比如在多线程环境中。可以同时使用 volatile
和 const
修饰一个变量,表示变量是只读的,但其值可能会被外部因素修改。
#include <iostream>
volatile const int* ptr; // 指向 volatile 和 const 的指针
int main() {
static int value = 42;
ptr = &value;
std::cout << "Value: " << *ptr << std::endl;
return 0;
}
const_cast
const_cast
用于移除 const
限定符,但要谨慎使用,因为这可能导致未定义行为。
#include <iostream>
void modifyValue(const int& value) {
int& nonConstValue = const_cast<int&>(value);
nonConstValue = 20;
}
int main() {
int x = 10;
std::cout << "Before: " << x << std::endl;
modifyValue(x);
std::cout << "After: " << x << std::endl;
return 0;
}
static const 数据成员
类的 static const
数据成员可以存储类级别的常量信息,通常需要在类外部初始化。
#include <iostream>
class MyClass {
public:
static const int staticValue;
};
const int MyClass::staticValue = 42; // 在类外部初始化
int main() {
std::cout << "Static Value: " << MyClass::staticValue << std::endl;
return 0;
}