一. const指针
int *p;
定义了一个普通的指针p
而const指针一般有一下几种:
// 指向常量的指针
1:const int *p; // 等价于int const *p;
2:int const *p;
// 常量指针
3:int * const p;
// 指向常量的常量指针
4:const int * const p;
下面我们来讲一讲它们的区别
![](https://i-blog.csdnimg.cn/blog_migrate/14ea9cbba4242df17dfa88c7ce8072ff.png)
1.1 const int *p; 和int const *p;
const int n = 3;
int const n = 3; // 两者等价
const与int谁写前都不影响语义
所以说1和2定义的指针是一样的
const int *p; // 定义了一个
// 等价于int const *p;
这里const 修饰的是整个*p
,所以你只要记住*p
不能被赋值,也就是不能作为左值
例如:
int q = 5;
int const *p = &q;
// 错误 *p是const,不能作为左值
// *p = 7;
const int q2 = 7;
// 正确 p不是const
p = &q2;
1.2 int *const p;
int *const p;
const 修饰的是p
,说明p是不能被赋值的,也就是不能作为左值,它只能永远指向初始化时的内存地址了
而此时整个*p
的前面没有const 的修饰。也就是说,*p是变量而不是常量
,所以我们可以通过*p
来修改它所指内存的值
例如:
int q = 5;
int * const p = &q;
// 正确 *p不是const
*p = 7;
const int q2 = 7;
// 错误 p是const,不能作为左值
// p = &q2;
1.3 const int *const p;
此时*p前有const,而且也有const直接在p前面
所以p的值不能改,*p的值也不能修改
例如:
int q = 5;
const int * const p = &q;
// 错误 *p是const,不能作为左值
// *p = 7;
const int q2 = 7;
// 错误 p是const,不能作为左值
// p = &q2;
1.4 辨析技巧总结
1)如果*p
前有const修饰,则不能改的是*p(
即不能类似这样*p=50;
赋值)
2)如果p
前有const修饰(const和p中间没有*),const 是直接写在p前,则p不能被赋值(即不能类似这样p = &a
赋值)
3)const与int谁写前都不影响语义
注意:不能被更改或不能被赋值的意思就是,不能作为左值
1.5 指针与const进一步说明
(1)要想存放常量对象的地址,只能使用指向常量的指针const int *p;形式
综合示例:
下面的代码错误的原因是,虽然你把p设为了const,但*p不是const,*p会改变q的值,这与q是个const常量矛盾了
(2)指针类型一般要与其指向的对象类型一致,但有例外
C++允许令一个指向常量的指针指向一个非常量对象
例如:
int q = 5;
int const *p = &q; // 正确:但是不能通过*p去修改q的值
*p = 3; // 错误
q = 8; // 正确
引用其实也有这种例外情况
对const的引用可以引用一个并非const的对象
int doinb = 1900;
const int &jingugu = doinb;
doinb += 10; // 正确
jingugu += 10; // 错误
解释:所谓指向常量的指针仅仅要求不能通过该指针去改变对象的值,而没有规定那个对象的值不能通过其他途径改变
二. const引用
2.1 int const &b = a;和const int & b = a;
const引用和const指针略有不同
int &const b = a;
是非法的- 不过
int const & b = a;
和const int & b = a;
仍然是等价的
int a = 3;
int const & b = a;
const int & b = a; // 等价于int const & b = a;
// int &const b = a; wrong
int &const b = a;
是非法的,因为指针是对象,而引用不是对象,所以指针可以被定义为const,而引用没有这种用法,所以不存在常量引用
2.2 引用的类型一般与所引用对象的类型一致,但有例外
(1)允许一个常量引用绑定非常量对象、字面值、甚至是表达式
int i = 42;
const int &r1 = i; // 正确
const int &r2 = 3; // 正确
const int &r3 = i * 5; // 正确
int &r4 = r1 * 2; // 错误
允许这种用法也能理解,因为我们经常要尝试避免函数对外面的变量进行修改
void f(const int*x) {
...
}
int a = 15;
f(&a); // 防止f修改外面的变量a
- 当要传入的参数类型比地址大的时候,我们通常传入const指针:这样既能用比较少的字节数传递值给参数,又能避免函数对外面的变量的修改
(2)非常量引用不能绑定表达式或字面值
2.3 题外话:为什么有时还会听到常量引用呢?
那是因为C++程序员们经常把词组“对const的引用”简称为“常量引用”,你要时刻记住它只是个简称,严格来说,并不存在,因为引用不是一个对象,所以我们没有办法让引用本身恒定不变。
可由于C++语言不允许随意改变引用所绑定的对象,所以从这层意义上可以理解所有的引用是“常量”
三、补充static const和const static是一样的
They mean exactly the same thing. You’re free to choose whichever you think is easier to read
Stackoverflow:static const versus const static
class MyClass {
public:
private:
const static int var = 0; // Option 1
static const int var = 0; // Option 2
};
参考资料