C++中const总结

c++中const用法总结

引言

const在c++中是一种限定符(qualifier),用来修饰变量类型、形参类型、函数、指针、类等一系列用法,用的时候不是弄得很蒙,比如指向常量的指针(pointer to const)与常量指针(const pointer),因此在此文中区分这些用法,以及限定符的作用是什么。

基本含义

const 修饰意为恒定的,不变的,当修饰变量的时候,意思是该变量在创建后是不可修改的,因此常量的声明和定义是在一条语句内完成的。常量是指本身不可修改,但可以被拷贝,去为其他变量赋值。通常常量在编译的时候还会被字面量替代。

1
2
3
4
5
const int bufferSize = 512; // ok
const int bufferSize; //error
const int i = getSize();

int a = i; // ok copy const value to a variable

常量引用

想要引用常量,必须使用常量引用(reference to const),否则可能会改变原值。

1
2
3
const int a = 1;
const int &b = a; //ok,both reference and underlying object are const
int &c = a; //error unconst reference to a const object

常量引用的初始化可以是一个非常量、常量、字面量、表达式,常量只能给常量引用初始化。常量引用后面的真实引用值不一定是常量。

1
2
3
4
5
int i = 1;
const int &r1 = i; //ok
const int &r2 = 3; //ok
const int &r3 = r1*2; //ok
int &r4 = 3; //error

常量指针与常指针

常量指针与常量引用类似,不可以通过该引用或指针修改背后的值,但背后的值是不是常量是不确定的。

1
2
3
4
5
6
const double pi = 3.14;
double *p1 = π //error
const double *ptr = π // ok

double dval = 3.14;
ptr = &dval; //ok but cannt change dval through ptr

常指针是指该指针一旦绑定一个地址,就不可以再改变了,所以一定要在声明的时候初始化。做法是再*后面加const修饰符。

  • 常量指针是指不能改变指向的对象
  • 常指针是指不能改变指向的对象
1
2
3
4
5
int a = 0;
int *const b = &a;

const int c = 1;
const int *const cptr = &c;

常量表达式

常量表达式(constant expression)是值不可以改变而且在编译的时候评估该值。

1
2
3
4
const int max_files = 20; // max_files is constant expression
const int limit = max_file + 1; // limit is constant expression
int staff = 20; // staff is not constexpr
const in sz = get_size() //sz is not constexpr

可以用constexpr 声明一个变量是常量表达式,这样再编译的时候就会展开表达式。

类成员函数后面加const

表示const对象只能调用带const标记的函数,const函数可以重载。
例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class A {
public:
int a = 0, b = 0;
A() = default;
A(int _a, int _b): a(_a),b(_b) {
std::cout << "call constructor" << std::endl;
}

int get_a() const {
std::cout << "call const get_a" << std::endl;
return a;
}

int get_a() {
std::cout << "call get_a" << std::endl;
return a;
}

int get_b() {
return b;
}
};

int main() {
const A a;
A b(1 ,2);
std::cout << a.get_a() << std::endl; //ok
// std::cout << a.get_b() << std::endl; //error
std::cout << b.get_a() << std::endl; //ok
std::cout << b.get_b() << std::endl; //ok

}