const基本上就像你做出的承诺,它承诺某些东西将是不可变的。但你可以绕过这个限制。
const的位置在类型说明符前或后具有相同的语义效果。
1
2
3
4
5
6
7
8
|
// const的位置在类型说明符前或后具有相同的语义效果。
const int a = 5; // 标准写法
int const b = 10; // 替代写法
// 指针场景下
// 两种写法完全等效,const修饰的都是指针指向的数据,而不是指针本身
const int* ptr1 = nullptr; // 标准写法
int const* ptr2 = nullptr; // 替代写法,注意:int* const ptr2 = nullptr; 这就是不同的意思了
|
- 两种写法表示的意思完全相同
- 编译后生成的二进制代码完全相同
- 区别仅在于代码风格(重要程度:⭐)
明确了上面的不同点之后我们再来看下面的具体用法
这种写法就类似别的语言中定义常量。
1
2
3
4
5
6
7
8
|
const int MAX_AGE = 110; // MAX_AGE 不能修改
std::cout << MAX_AGE << std::endl;
/* 通过指针可以绕过const限制,但你总是不应该这么做。 */
int* ptr = new int;
ptr = (int*)&MAX_AGE;
*ptr = 100;
std::cout << *ptr << std::endl;
|
通过上面的例子告诉你,被const修饰的对象并不是一定不能修改,const只是给编译器看的。
1
2
3
4
5
6
7
8
9
10
11
12
|
const int* ptr2 = new int; // const int* ptr2 表示不能改变指针指向的地址上的内容
ptr2 = (int*)&MAX_AGE;
//*ptr2 = 100;
std::cout << *ptr2 << std::endl;
int* const ptr3 = new int; // int* const ptr3 表示不能改变ptr3指针本身
//ptr3 = (int*)&MAX_AGE;
*ptr3 = 100;
std::cout << *ptr3 << std::endl;
// 还可以合在一行,一个const修饰的是int指针指向的数据,一个const修饰的是指针本身
const int* const ptr3 = nullptr;
|
理解记忆口诀:"左定数据,右定针,两边都定双保险"
- 左边const(const T*):数据不可变
- 右边const(T* const):指针不可变
- 两边const(const T* const):数据指针都不变
我个人也理解为const在前不看*,const在后要看*
const在类中声明在方法名后时,表示该方法不修改任何类成员。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
class Person
{
private:
int m_Age;
public:
int GetAge() const
{
// m_Age = 20; // 因为方法名后声明了const,因此不允许修改任何类成员(注意是编译器不允许,并不是底层不能修改。说白了const是一套给编译器看的规则。)
return m_Age;
}
void SetAge(int x)
{
m_X = x;
}
};
|
const 用在函数参数上,表示不能在函数中修改被修饰的对象
1
2
3
4
|
void PrintPerson(const Person& p)
{
std::cout << p.GetAge() << std::endl;
}
|
1
2
3
4
5
6
7
8
9
10
|
class Person
{
private:
int* m_Age;
public:
const int* const GetAge() const // 表示该方法返回的指针指向的数据不能被修改,并且该指针本身不能被修改,并且该方法也不修改类中的任何成员。
{
return m_Age;
}
};
|
- const基本上就像你做出的承诺,它承诺某些东西将是不可变的。
- const是可以绕过的,const只是给编译器看的