3. 认识 const
1. const 位置
- 除了修饰一个类的成员函数外,不会出现在一条语句的最后。
- 引用本身可以理解为指针常量,在引用前使用 const 没有意义。
- 理解:先看离变量名最近的是啥
1.1 int const *p;
- 离 p 最近的是
*
,所以 p 首先是一个指针;接着,剩下的就是 p 指向的类型,也即 int const(整型常变量),所以 const 修饰的是 int,p 是一个常量指针。等价于const int *p;
。 - 也就是 p 指向的内容是不能改变的。
1.2 int * const p;
- 离 p 最近的是
const
,所以 p 是一个变量,类型是int * const
,所以 const 修饰的是 int*,p 是一个指针常量。 - 也就是 p 本身是不能改变的。
1.3 int const * *p;
- 离 p 最近的是
*
,p 首先是一个指针,指向的是int const *
。对于int const *
来说,首先是一个指针,指向的是int const
,所以是一个整型常量指针。所以 p 是一个指向整型常量的指针的指针。 - 也就是 p 指向的是一个地址,这个地址上还是另一个地址,这个另一个地址上的内容是不可修改的 int(整型常量)。
1.4 int * const * p;
- 离 p 最近的是
*
,p 首先是一个指针,指向的类型是int * const
(整型指针常量),const 修饰的是 int*。 - 也就是,p 指向的是一个地址,这个地址里面是另一个地址,这个另一个地址是不能被改变的。
这里 ptr_a 指向 a 的地址,ptr_a = a 的地址,所以 *ptr_a = a的内容;p 指向 ptr_a 的地址,p = ptr_a 的地址,所以 *p = ptr_a 的内容,也就是 a 的地址。
2. const 对象和对象的 const 成员
- 用 const 修饰的类的对象称为常对象,用 const 修饰的类成员函数称为常函数。
#include <iostream>
using namespace std;class A {int num;
public:A() { num = 5;} void disp();void disp() const;void set(int n) { num = n; }
};void A::disp() {cout << num << endl;
}void A::disp() const {cout << num << endl;
}int main() {A a1;a1.set(3);a1.disp();A const a2;a2.disp();return 0;
}
- 声明和定义部分:
- const 函数的声明和定义分开时,都需要加上 const,否则编译报错。
- 只有类的非静态成员函数可以被声明为 const,原因是静态成员函数不含 this 指针,属于类级别的函数。
- 普通函数不能声明为 const。
- 在非 const 对象中,部分数据成员可以 const 修饰。类对象的非静态常量成员只能借助初始化列表进行初始化。构造函数中通过赋值运算符进行的是赋值,不是初始化。
- 构成重载关系:
- 一个类的两个成员函数,一个 const 函数,一个普通函数,将构成重载关系,返回值类型、函数名、函数的参数列表完全相同。
- 如:一个被看成 void disp(A*),一个看成 void disp(const A*),从而构成重载。
- 对于非 const 对象 a1,先寻找普通函数,再寻找 const 版本。对于常对象 a2,只能调用 const 版本。
- 一个类的两个成员函数,一个 const 函数,一个普通函数,将构成重载关系,返回值类型、函数名、函数的参数列表完全相同。
- 当存在 const 版本和普通版本的成员函数时,若普通对象想调用 const 成员函数,则需要通过建立该对象的常引用或者指向该对象的常指针来实现。比如:
( (const A&)a1).disp();
或者( (const A*)&a1)->disp();
。
3. const 修饰函数参数和函数的返回值
- 函数参数和返回值的 const,主要为了让编译器检查只读。
- 当 const 修饰数值类型的形参时,不构成函数重载,如 void disp(const int i) 和 void disp(int i)。
- 但当 const 修饰的是引用或指针的形参时,就是重载,如 void disp(const int& i) 和 void disp(int& i)。
4. 常见的 const 错误理解
- const 修饰的变量一定不能修改,错误。
- 当 const 修饰的局部变量存储在非只读存储器中,通过指针可以间接修改。
- const 引用和 const 指针只能指向常变量,错误。
- const 引用和 const 指针,只能说明不能通过该引用或指针去修改被引用的对象,至于被引用对象原来是什么性质是无法通过 const 引用和 const 指针决定的。
5. const ⇒ 非 const
C++ 中的 const_cast
可以去除 const 或 volatile 属性。
- const_cast 只能去除目标的 const 或 volatile 属性,不能进行不同类型的转换。如下,不能由 const int[ ],转换为 int&。
- const_cast 取消的是间接引用时的改写权限,变量原来的 const 不能去除。
6. C++ 和 C 中的 const 区别
- 通常 C++ 碰见 const 声明时在 符号表 中放入常量
- 编译过程中若发现使用常量则 直接以符号表中的值替换
- 编译过程中若发现下述情况则给对应的常量分配空间:
- 对 const 常量 使用了 extern
- 对 const 常量 使用了 & 操作符