前言:认真学习一下 C++,感觉光会 Go 没啥用。读一读《C++ Primer》
基本知识
- const 对象一旦创建后其值就不能再改变,所以 const 对象必须初始化。一如既往,初始值可以是任意复杂的表达式。
- 默认情况下,const 对象仅在文件内有效。
针对第一点:
- 如果利用一个对象去初始化另外一个对象,则它们是不是 const 都无关紧要。
- const 只是一个限定符,保证当前的变量不对这个对象修改,但不保证原有的对象其他方式的修改。
针对第二点:
- 如何定义一次并可以在多个文件中使用同一个 const 变量?
解决办法是:对于 const 比纳凉不管是声明还是定义都添加 extern 关键字,这样只需要定义一次就可以了。
// file_1.cc 定义并初始化了一个常量,该常量能被其他文件访问
extern const int bufSize = fcn();
// file_1.h 头文件
extern const int bufsize; // 与 file_1.cc 中定义的 bufSize 是同一个
Const 的引用
首先我们来看一个例子:
double dval = 3.14;
const int &ri = dval;
这个是没有语法错误的。但是:
double dval = 3.14;
int &ri = dval;
这个是有错误的。
原因在于,上述类型转换的过程中,会产生临时变量。引用的是临时变量。由于前者只读所以引用临时变量没问题。但是后者可写,修改一个临时变量就毫无意义,所以语法上是错误的。
而且,我们还可以知道:
对 const 的引用可能引用一个并非 const 的对象
指针和 const
- 想要存放常量对象的地址,只能使用指向常量的指针
- 但是指向常量的指针,可以指向一个非常量的对象,而且我们不能通过这个指针修改原来的对象。例子如下:
double pi = 3.14;
const double *cptr = π
什么是顶层/底层 const
首先我们要知道这样一句话:
对于一个指针来说,它本身是不是常量以及它指向的对象是不是常量是两回事。所以顶层 const 表示指针本身是一个常量,底层 const 表示指针所指的对象是一个常量。比如:
const int* p1; // 底层 const,p1 指向的对象是一个常量,不能通过 p1 修改
int *const p2; // 顶层 const,p2 本身是一个常量,不能修改
当执行对象的拷贝操作时,常量是顶层 const 还是底层 const 区别明显:顶层 const 几乎不受什么影响,但是底层 const 不行。比如:
int t1 = 10;
const int* p1 = &t1;
int* p2 = p1; // 错误,p1 是一个指向 const int 的指针,底层 const
常量表达式和 constexpr
常量表达式:是指值不会改变并且在编译过程就能得到计算结果的表达式。c++11 新标准规定,允许将变量声明为 constexpr 类型以便由编译器来验证变量的值是否是一个常量表达式。声明为 constexpr 的变量一定是一个常量,而且必须用常量表达式初始化
constexpr int mf = 20;
constexpr int limit = mf + 1;
constexpr int sz = size(); // 只有 size 是一个 constexpr 函数时才是一条正确的声明语句
一般来说,如果你认定变量是一个常量表达式,那就把它声明成 constexpr 类型。
而且必须明确一点,在 constexpr 声明中如果定义了一个指针,限定符 constexpr 仅对指针有效,与指针所指的对象无关。(其实就是一个顶层 const)比如:
const int *p = nullptr; // p 是一个指向整数常量的指针
constexpr int *q = nullptr; // q 是一个指向整数的常量指针
Const 对象类型判断
顺时针法则。再对 const 上又有些不一样。按具体例子来分析
const 是一个限定符,具体什么类型,要看后面比如:
const int 整数常量
- int const a
按照顺时针法则:
- a 是一个常量
- a 是一个 int 常量
- const int a
按照顺时针法则:
- a 是一个整数
- a 是一个常量 int
所以 const int 和 int const 一致
- int *const a
按照顺时针法则:
- a 是一个常量
- a 是一个指向 int 的常量指针
- const int* a
- a 是一个指针
- a 是一个指向常量 int 的指针
网友评论