const 限定符
C++ const 允许指定一个语义约束,编译器会强制实施这个约束,允许程序员告诉编译器某值是保持不变的。如果在编程中确实有某个值保持不变,就应该明确使用const,这样可以获得编译器的帮助。
const 与常量
①.const 修饰变量
用 const 修饰一个变量,表示该变量一旦创建,则值不可以被更改;定义一个 const 变量,则必须进行初始化。
const int a = 12;//编译时初始化
const int b = getsize();//运行时初始化
a = 10;//报错,const 变量禁止赋值
②.初始化和 const
当用一个对象对初始化另外一个对象时,他们是不是 const 都无关紧要,因为拷贝不改变原对象内容。
int i = 42;
const int c = i;// i 的值 拷贝给 c
int j = c;
③.extern const
一个对象可以有多次声明,但定义只能一次。如果要在多个文件之间共享 const 对象,必须在变量定义之前添加 extern 关键字。
// test1.cpp
extern const int a = 10; //定义一个 const 变量 a,该常量能被其他文件访问
//test2.cpp
extern const int a;// 仅声明一个 const 变量 a,该常量的定义可以在其他文件中找到
禁止在头文件中用 extern 定义变量,若该头文件被多个文件包含时,将会出现重复定义错误。
// test.h
extern const int a = 10;
// test1.cpp
#include "test.h"
// 编译出错,重复定义错误
④.const 和 #define
#define 是在编译的预处理阶段起作用;而 cons t是在 编译、运行的时候起作用。
#define 只是简单的字符串替换,没有类型检查;const 定义的常量,在编译时进行严格的类型检验,可以避免出错。
#define 只是进行展开,有多少地方使用就替换多少次,内存中有若干个备份;const 定义的只读变量在程序运行过程中只有一份备份。
因此对于单纯常量,最好以 const 对象替换 #define。
const 与引用
①.const 的引用
可以把引用绑定到 const 对象上,称为对常量的引用;对常量的引用不能被用做修改它所绑定的对象。
const int c = 1024;
const int &r = c;// r 是 c 的引用
②.引用非 const 对象
常量引用仅对引用可参与的操作进行了限定,对引用对象本身是不是常量未做限定。
int i= 12;
const int &r = i;// r 是常量引用,但绑定的对象 i 非 const
const 与指针
①.指向常量的指针
要想存放常量对象的地址,只能使用指向常量的指针;指向常量的指针不能用于改变其所指对象的值。
const a = 3;// a 是一个常量
int *p = &a;//错误 , p 是一个普通指针
const int *p1 = &a;// p1 是一个指向常量的指针
同引用,指向常量的指针对其所指对象是否是常量没有限制。
②.顶层 const
当关键字 const 出现在星号的右边,则为:顶层 const ;表示指针本身是个常量,不能改变指针本身的值。
int i = 2;
int * const ptr= &i;//ptr是一个顶层const,将一直指向 i,不能改变 ptr 的值
③.底层 const
当关键字 const 出现在星号的左边,则为:底层 const ;表示指针所指对象是个常量,不能改变所指对象的值。
int i = 2;
const int * ptr= &i;//ptr是一个底层const,可以改变 ptr 的值,但不能改变所指对象的值
const 与函数
①.const 修饰函数参数
可以表示传递过来的参数,在函数内不可以被修改;并无实际意义,因为函数会自动产生临时变量复制实参值,并不会对原对象进行更改。
void int f1(const int a)
{
// 在函数内不可以改变 a 的值
}
可以表示参数指针所指的内容为常量,不可以改变。
void int f2(const int *a)
{
// 在函数内不可以改变 *a 的值
}
可以表示参数指针本身为常量,不可以更改;也无实际意义,因为参数指针也是形参。
void int f3(const int * const a)
{
// 在函数内不可以改变 a 的值
}
自定义类型的参数传递,需要临时对象复制参数,对于临时对象的构造,需要调用构造函数比较浪费时间,因此采取引用传递的方法。可以用 const 限定 增加效率同时防止被修改。
void int f4(const T & a)
{
// 在函数内不可以改变 a 的值
}
②.const 修饰函数返回值
函数返回值是值传递时,用 const 修饰返回值没有任何意义,因为函数会把返回值复制到外部临时的存储单元中。
const int f1();//
函数返回值类型是指针并用 const 修饰时,该返回值只能被赋给加const 修饰的同类型指针。
const int * f2();//调用时,const int * p1 = f2();
int * const f3();//调用时,int * const p2= f3();
一般情况下,函数的返回值为某个对象时,如果将其声明为 const 时,用于限制不能将函数表达式作为左值使用。
const int & min ( int &i, int &j);
min(a,b) = 4;//出错
const 与类
①.const 修饰成员变量
用 const 修饰类的成员变量,表示成员常量,不可以被修改,也只能再初始化列表中被赋值
class A
{
const int val;//成员常量不可以被修改
A(int v):val(x){};//只能再初始化列表中赋值
}
②.const 修饰成员函数
用 const修饰类的成员函数,则该成员函数不能修改类中任何成员,一般写在函数的最后来修饰。
class A
{
void function() const;//不可以修改对象的成员变量,也不能调用非 const 成员函数
}
③.const 修饰类对象
用 const 修饰类对象表示该对象为常量对象,其中的任何成员都不能被修改;对于对象指针和对象引用也是一样。
用 const 修饰的对象,该对象的任何非 const 成员函数都不能被调用。
class A
{
void function1() const;
void function2() ;
}
const A *obj = new A();
A->function1();//正确
A->function2);//错误,const 对象只能调用 const 成员函数
④.const 修饰成员函数修改成员变量
可以使用 mutable 关键字修饰成员,则该变量在 const 成员函数中也可以被修改。
class A
{
mutable int _ct;
void function() const
{
_ct++;//正确
};
}
const 转换
①.去 const 限定
使用 const_cast 可以去除变量的 const 限制:常量指针被强制转为非常量指针,仍然指向原来对象;常量引用被强制转为非常量引用,仍然指向原来对象;常量对象被强制转为非常量对象。
const A *obj = new A();//A 指向的对象不可用被更改
A * ptr = const_cast<A*>(obj);// ptr 和 obj 指向同一个对象,ptr 可以更改对象
const A a;
A b = const_cast<A>(a);//去 const 属性后赋值给一般变量
②.增加 const 限定
也可以使用 const_cast 、 static_cast 将非 const 对象增加 const 限定。
A *obj = new A();
const A * ptr = static_cast<const A*>(obj);//obj 增加 const 限定