const 是不变的意思,修饰内置类型变量、自定义对象、成员函数、返回值,函数参数。

# 修饰普通类型变量

变量的值不能被修改。

#include <iostream>
using namespace std;
int main() {
	int a = 1;
	cout << "a: " << a << endl;
	a = 2;
	cout << "a++: " << a << endl;
	const int b = 2;
	cout << "b: " << b << endl;
	// b = 2; error: assignment of read-only variable ‘b’
}

输出:

a: 1
a++: 2
b: 2

如果把常量的地址赋给非常量指针,修改指针的值,常量的值也不会被改变。

#include <iostream>
using namespace std;
int main() {
	const int b = 2;
	cout << "b: " << b << endl;
	// b = 2; error: assignment of read-only variable ‘b’
	int* a = (int*) &b;
	cout << "a: " << *a << endl;
	*a = 3;
    cout << "a: " << *a << endl;
	cout << "b: " << b << endl;
}

输出:

b: 2
a: 2
a: 3
b: 2

加上 volatile 修饰符,常量的值就会被改变。

#include <iostream>
using namespace std;
int main() {
	volatile const int b = 2;
	cout << "b: " << b << endl;
	// b = 2; error: assignment of read-only variable ‘b’
	int* a = (int*) &b;
	cout << "a: " << *a << endl;
	*a = 3;
    cout << "a: " << *a << endl;
	cout << "b: " << b << endl;
}

输出:

b: 2
a: 2
a: 3
b: 3

# 修饰指针变量

分为三种情况:

  • 修饰指针指向的内容,则内容为不可变量。
  • 修饰指针,则指针为不可变量。
  • 修饰指针和指针指向的内容,则指针和指针指向的内容都为不可变量。
#include <iostream>
using namespace std;
int main() {
	int a = 1;
	int b = 2;
	const int* c = &a;
	cout << "const int* c: " << *c <<endl;
	// *c = 2; error: assignment of read-only location ‘* c’
	c = &b;
	cout << "c = &b: " << *c << endl;
	int* const d = &a;
	cout << "int* const d: " << *d << endl;
	*d = 3;
	cout << "*d = 3: " << *d << endl;
	// d = &b; error: assignment of read-only variable ‘d’
	const int* const e = &a;
	// *e = 4; error: assignment of read-only location ‘*(const int*)e’
	// e = &b; error: assignment of read-only variable ‘e’
}

输出:

const int* c: 1
c = &b: 2
int* const d: 1
*d = 3: 3

# 修饰引用

修饰引用时,对应变量的值不可改变。

#include <iostream>
using namespace std;
int main() {
  const int& b = 10;
  // b = 20; error: Cannot assign to variable 'b' with const-qualified type 'const int &'
}

# 修饰函数参数

修饰参数时,分为三种情况:

  • 修饰值传递变量,一般这种情况不需要 const 修饰,因为函数会自动产生临时变量复制实参值,这种情况函数内不能修改参数值。
  • 修饰指针参数,指针不能被修改,同指针变量。
  • 自定义类型的参数传递,需要临时对象复制参数,对于临时对象的构造,需要调用构造函数,比较浪费时间,因此我们采取 const 外加引用传递的方法。
#include <iostream>
using namespace std;
class A {
public:
	A() {}
	A(int a):a(a) {}
	int get_a() const {
		return a;
	}
	void add_a() {
		++a;
	}
private:
	int a;
};
void func1(const int a) {
	// ++a; error: increment of read-only parameter ‘a’
	cout << "const int a: " << a << endl;
}
void func2(const int* a) {
	// ++*a; error: increment of read-only location ‘* a’
	cout << "const int* a: " << *a << endl;
	int b = 2;
	a = &b;
	cout << "a = &b: " << *a << endl;
}
void func3(int* const a) {
	cout << "int* const a: " << *a << endl;
	++*a;
	cout << "++*a: " << *a << endl;
	int b = 2;
        // a = &b; error: assignment of read-only parameter ‘a’
}
void func4(const int* const a) {
	cout << "const int* const a: " << *a << endl;
	// ++*a;  error: increment of read-only location ‘*(const int*)a’
	int b = 2;
	// a = &b; error: assignment of read-only parameter ‘a’
}
void func5(const A a) {
	cout << "const A a: " << a.get_a() << endl;
	// a.add_a(); error: passing ‘const A’ as ‘this’ argument of ‘void A::add_a()’ discards qualifiers [-fpermissive]
}
void func6(const A* a) {
	cout << "const A* a: " << a -> get_a() << endl;
	// a -> add_a(); error: passing ‘const A’ as ‘this’ argument of ‘void A::add_a()’ discards qualifiers [-fpermissive]
	A bb(4);
	a = &bb;
	cout << "a = &b: " << a -> get_a() << endl;
}
void func7(A* const a) {
	cout << "A* const a: " << a -> get_a() << endl;
	// a.add_a(); error: request for member ‘add_a’ in ‘a’, which is of pointer type ‘A* const’ (maybe you meant to use ‘->’ ?)
	A bb(4);
        // a = &bb; error: assignment of read-only parameter ‘a’
}
void func8(const A* const a) {
	cout << "const A* const a: " << a -> get_a() << endl;
	// a.add_a(); error: request for member ‘add_a’ in ‘a’, which is of pointer type ‘const A* const’ (maybe you meant to use ‘->’ ?)
	A bb(4);
	// a = &bb; error: assignment of read-only parameter ‘a’
}
void func9(const A& a) {
	cout << "const A& a: " << a.get_a() << endl;
	// a.add_a(); error: passing ‘const A’ as ‘this’ argument of ‘void A::add_a()’ discards qualifiers [-fpermissive]
	A bb(4);
	// a = &bb; error: passing ‘const A’ as ‘this’ argument of ‘A& A::operator=(const A&)’ discards qualifiers [-fpermissive]
}
int main() {
	int a = 1;
	func1(a);
	func2(&a);
	func3(&a);
	func4(&a);
	A aa(3);
	func5(aa);
	func6(&aa);
	func7(&aa);
	func8(&aa);
	func9(aa);
}

输出:

const int a: 1
const int* a: 1
a = &b: 2
int* const a: 1
++*a: 2
const int* const a: 2
const A a: 3
const A* a: 3
a = &b: 4
A* const a: 3
const A* const a: 3
const A& a: 3

# 修饰函数返回值

  • 如果函数返回值采用 “值传递方式”,由于函数会把返回值复制到外部临时的存储单元中,加 const 修饰没有任何价值。
  • 如果给以 “指针传递” 方式的函数返回值加 const 修饰,那么函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加 const 修饰的同类型指针;
#include <iostream>
using namespace std;
class A {
public:
	A() {}
	A(int a):a(a) {}
	int get_a() const {
		return a;
	}
	void add_a() {
		++a;
	}
private:
	int a;
};
const int func1() {
	return 1;
}
const A func2() {
	return A(3);
}
const A func3() {
	A a(6);
	return a;
}
const A* func4() {
	A a(8);
	A* b = &a;
	return b;
}
const A& func5() {
	A a(9);
	A& b = a;
	return b;
}
int main() {
	int a = func1();
	cout << "int: " << a << endl;
	cout << "++a: " << ++a << endl;
	const int b = func1();
        cout << "const int: " << b << endl;
        // cout << "++b: " << ++b << endl; error: increment of read-only variable ‘b’
	A c = func2();
	cout << "A: " << c.get_a() << endl;
	c.add_a();
	cout << "c.add_a(): " << c.get_a() << endl;
	c = A(5);
	cout << "c = A(5): " << c.get_a() << endl;
	const A d = func2();
        cout << "const A: " << d.get_a() << endl;
        // d.add_a(); error: passing ‘const A’ as ‘this’ argument of ‘void A::add_a()’ discards qualifiers [-fpermissive]
        // d = A(5); error: passing ‘const A’ as ‘this’ argument of ‘A& A::operator=(const A&)’ discards qualifiers [-fpermissive]
	A e = func3();
        cout << "A: " << e.get_a() << endl;
        e.add_a();
        cout << "e.add_a(): " << e.get_a() << endl;
        e = A(7);
        cout << "e = A(7): " << e.get_a() << endl;
	const A f = func3();
	cout << "const A: " << f.get_a() << endl;
	// f.add_a(); error: passing ‘const A’ as ‘this’ argument of ‘void A::add_a()’ discards qualifiers [-fpermissive]
	// f = A(7); error: passing ‘const A’ as ‘this’ argument of ‘A& A::operator=(const A&)’ discards qualifiers [-fpermissive]
	// A g* = func4(); error: expected initializer before ‘*’ token
	const A* h = func4();
	cout << "const A*: " << h -> get_a() << endl;
	// h -> add_a(); error: passing ‘const A’ as ‘this’ argument of ‘void A::add_a()’ discards qualifiers [-fpermissive]
	// A& i = func5(); error: invalid initialization of reference of type ‘A&’ from expression of type ‘const A’
	const A& j = func5();
	cout << "const A&: " << j.get_a() << endl;
	// j.add_a(); error: passing ‘const A’ as ‘this’ argument of ‘void A::add_a()’ discards qualifiers [-fpermissive]
}

输出:

int: 1
++a: 2
const int: 1
A: 3
c.add_a(): 4
c = A(5): 5
const A: 3
A: 6
e.add_a(): 7
e = A(7): 7
const A: 6
const A*: 8
const A&: 9

# 修饰类成员函数

在上面可以发现,const 类型的指针或引用可以调用 get_a () 方法,这是因为其后有 const 修饰,认为这个方法不会改变对象的值。
如果被 const 修饰的成员函数想要修改成员变量的值,可以使用 mutable 修饰成员变量,表示可变化的。

#include <iostream>
using namespace std;
class A {
public:
	A() {}
	A(int a, int b):a(a),b(b) {}
	int get_a() const {
		// ++a error: increment of member ‘A::a’ in read-only object
		return a;
	}
	int get_b() const {
		++b;
		return b;
	}
	void add_a() {
		++a;
	}
private:
	int a;
	mutable int b;
};
int main() {
	A aa(1, 1);
	cout << "aa.a=" << aa.get_a() << endl;
	cout << "aa.b=" << aa.get_b() << endl;
}

输出:

aa.a=1
aa.b=2