const限定符
2023年11月22日 2023年12月31日
说明
类型修饰符
采用《C++ Primer》中的概念, 和常量指针,指针常量,常量引用这些概念相冲突
不使用以下定义:
- | |
---|---|
常量指针 pointer to const |
指向常量的指针 |
指针常量 const pointer |
指针是常量 |
常量引用 const reference |
引用常量 |
使用以下定义:
- | ||
---|---|---|
具有顶层const的指针 | const pointer | const指针 |
具有底层const的指针 | pointer to const | |
具有底层const的左值引用 | reference to const | const引用 |
不涉及迭代器
顶层const
-
描述对象自身的读写权限
只有对象能拥有顶层const属性:- 引用是变量不是对象,不能拥有顶层const
- 指针是对象, 可以拥有顶层const
- 引用是变量不是对象,不能拥有顶层const
-
拥有顶层const的对象只读,必须显式初始化
1const T var = val;
具有顶层const的指针
const指针
具有顶层const属性的指针
- 不可指向其他对象: 不能对具有顶层const的指针指向写操作,即不能使其指向其他对象
- 指向对象的读写权限不受影响
1T var, * const cp = &var;
底层const
指针和引用可间接访问对象
-
描述间接访问对象读写权限的开放情况
基于间接访问,只有引用和指针可以拥有底层const属性 -
如果指针和引用拥有底层const,通过二者间接访问对象时, 无法执行写操作
间接访问对象不一定具有顶层const,但对指针和引用锁定写权限 -
如果指针不具有顶层const属性, 可以修改指针指向
指针之间的赋值过程中, 底层const属性被传递,要求左右两侧运算对象的底层const一致
初始化引用和指针时,如果间接访问对象具有顶层const,要求引用和指针具有底层const
1int a = 5, *p = &a; 2const int * const cpc = p; // cpc具有顶层const和底层const 3const int b = 6; 4const int *pc = &b; // pc必须有底层const 5 6int *p2 = pc; // 错误:p2必须有底层const 7int &ri = b; // 错误:ri必须有底层const
具有底层const的指针
1const T *pc;
具有底层const的左值引用
const引用
1int i = 5; 2const int &rci = i; // 绑定对象锁定写权限 3i = 6; 4cout << rci<< endl; // 6 5cout << &rci<< endl << &i << endl; // 二者地址相同
可以用来绑定一个右值表达式
被绑定对象对具有底层const的左值引用锁定写权限
发生隐式转换时, 表达式为纯右值表达式, 纯右值表达式物质化得到速亡值表达式, 为一个即将销毁且无其他使用者的对象; 将引用绑定到该对象
初始值为表达式,或存在隐式类型转换,是纯右值表达式
纯右值表达式物质化得到速亡值表达式,对应一个明确对象,将引用绑定到该对象
1double dval = 3.14; 2const int &rci = dval; // 变量表达式是一个左值, 将其用来初始化rci时, 发生一次隐式转换, rci实际绑定的是隐式转换的结果 3 4// <=> 5// const int temp = dval; 6// const int &rci = temp; 7 8cout << &dval << endl << &rci << endl; // 二者地址不同 9cout << rci << endl; // 3 10 11 12const double &rcd = dval; // 使用rcd绑定dval 13cout << &dval << endl << &rcd << endl; // 二者地址相同
具有底层const的右值引用
间接访问对象对具有底层const的右值引用锁定写权限
1#include <iostream> 2int fcn(int a) { return a + 1; } 3int main() 4{ 5 int a = 5; 6 const int &&r = fcn(a); 7 r = 20; // 错误: 无法通过r读写绑定对象 8 9 int &&r2 = fcn(5); 10 r2 = 10; // 正确 11 return 0; 12}
定义同时具有顶层const和底层const的指针
具有底层const的const指针
1const int *p; // 具有底层const的指针 2 3int a; 4int *const cp = &a; // 具有顶层const的指针, 即const指针 5 6const int * const cpc = a; // 同时具有顶层const和底层const的指针
总结
- 所有对象都可以拥有顶层const,但只有支持间接访问的指针和引用可以拥有底层const
- 指针既可以拥有顶层const, 也可以拥有底层const
- 引用只能拥有底层const
const属性和作用域
- 在函数外声明的顶层const对象,具有文件作用域
- 在函数外声明的底层const对象,具有全局作用域
创建具有全局作用域的顶层const对象
声明或定义顶层const对象时,使用extern关键字,使之具有全局作用域
包含显式初始化的声明即定义,只能在一处定义
具有文件作用域的顶层const对象和具有全局作用域的顶层const对象,因为作用域不同,可以出现在同一个文件中
file实现
- 头文件
1void print();
- 定义
1#include <iostream> 2using std::cout; 3using std::endl; 4 5const int ci = 70; // 文件作用域 6extern const int ci; // 全局作用域 7 8void print() 9{ 10 cout << "In print:\n"; 11 cout << "ci = " << ci << endl; 12}
main函数测试
1#include <iostream> 2#include "file.h" 3 4using std::cout; 5using std::endl; 6 7extern const int ci = 7; // 顶层const:全局作用域 8 9int main() 10{ 11 cout << "In main:\n"; 12 cout << "ci = " << ci << endl; 13 14 print(); 15 return 0; 16}
-
编译
1g++ -std=c++11 file.cpp main.cpp
-
运行结果
In main: ci = 7 In print: ci = 70