C++中的const
const 对象
const最简单的用法是定义一个无法修改的变量。const对象一旦创建后其值就无法改变,所以const对象必须在定义的时候进行初始化。
const int i = get_size(); // 正确: 运行时初始化
const int j = 40; // 正确: 编译时初始化
const int k; // 错误: const对象必须在定义时初始化
默认情况下,const对象仅在当前文件内有效。如果要在多个文件中使用一个const,仍然要满足一次定义多次声明的原则,并且不管是声明还是定义都应该添加extern关键字。
类中的const成员必须在:
初始化列表中初始化。成员函数后的const表示该函数传入const this指针。
const 指针
指针提供了是一种间接访问对象的手段,同时它也是一种对象(需要分配存储空间)。自然地,一个指针对象可以定义成const,让它的内容保持不变,即地址不变,我们称之为表面const。但仅仅如此,并不能满足需求。当一个表面const的指针指向const对象时,要求地址不变并没有什么用,我们要求的是这个地址内的数据不被改变。需要一种区别于表面const的属性,称为底层const,他表示不能通过该指针改变所指向对象的值(当然没有要求这个指针变量本身的内容不变)。
- 表层const:
type * const point = &var;
既然指针本身不能改变,不能指向其它对象。它必须在定义时初始化。 - 底层const:
const type *point;
不能通过该指针的间接访问改变所指对象的值。可以不初始化。
当然一个指针可以同时有上面两种const修饰,成为一个不能指向其它对象而且不能改变所指对象的指针。
const 引用
在定义引用的前面加上const关键字,构成const引用。他表示不能通过这个引用来改变被引用的对象的值,而不是要求被引用的对象一定是const对象。引用本身不是对象,所以不存在是不是常量的问题。常量引用指的是不能通过此引用改变所引对象。
int i = 42;
const int j = 20;
const int &r = i; // ok
// r = 40; 尽管r所引用的变量不是const,但该引用是常量引用,不能通过常量引用修改所指向对象的值
// int r2 = j; 由于j是常量,指向它的引用必须是常量引用。(否则可以通过引用改变常量)
constexpr
常量表达式是指值不会改变应且在编译期间就能计算出结果的表达式。字面值属于常量表达式,用常量表达式初始化的const对象也是常量表达式。
constexpr是c++11引入的关键字,用来定义常量表达式、常量函数。
constexpr函数
constexpr修饰的函数在计算常量参数时可以在编译期由编译器计算出结果。
#include <iostream>
constexpr int add(int left, int right){
return left + right;
}
int get(){
return 20;
}
using std::cout;
using std::cin;
int main(){
int a = 10, b = 10;
cout << add(10, 10) << add(a, b) << add(get(), get()) << std::endl;
cin >> a;
cout << add(10, a);
return 0;
}
constexpr也可以用于替换以前的宏计算。
constexpr函数的限制:
- 函数中只能有一条语句且为return语句
- 只能调用其他constexpr函数
- 只能使用全局constexpr变量
注:可以使用?:
运算符条件返回;允许递归调用;只允许包含一条可执行代码。但允许包含typedefs
,using declaration
and directives
,static assertion
等。
一个声明为constexpr
的函数同样可以在运行时调用(参数非常量表达式时),所以不需要额外写同样功能的非constexpr
函数。
constexpr对象
内置类型的constexpr
对象必须要用常量表达式初始化,即编译期间能计算出结果的表达式。
如果要定义自定义类型的constexpr
对象,需要把该类的构造函数定义成constexpr
形式。
#include <iostream>
class Point{
public:
constexpr Point(int x = 0, int y = 0) :m_x(x), m_y(y) {}
private:
int m_x;
int m_y;
};
int main(){
constexpr Point p;
return 0;
}
注:如果一个成员函数是constexpr
的或者一个变量是constexpr
的,那么它们也是const的;反之不成立。const的变量可以运行时初始化,不必须在编译时初始化。