常类型也称为const类型,是指使用类型修饰符const说明的类型。const是c和c++中常见的关键字
在c语言中:它主要用于定义变量为常量类型以及修饰函数参数与返回值,而在C++中还可以修饰函数的定义
const的作用
定义const常量,具有不可变性。例如:
const int MAX = 100;
int Array[MAX];
(2) 进行类型检查,使编译器对处理内容有更多的了解,消除了一些隐患,例如:
void f(const int i) { ...}编译器知道i是一个常量,不允许修改。
(3) 避免意义模糊的数字出现,同样可以很方便的进行参数的调整和修改。同宏定义一样,可以做到不变则已,一变都变。如(1)中如果修改MAX的内容,只需要定义const int
MAX=期望值 即可。
(4)保护被修饰的东西,防止被以外修改,增强了程序的健壮性。
void(const int i) {
i = 10;// 编译器会报错
}
(5)为函数重载提供参考
class A {
void f(int i) {...} //定义一个函数
void f(inr i) const {...} // 上一个函数的重载
}
(6)节省空间,避免不必要的内存分配。例如:
#define PI 3.14159 // 该宏来定义常量
const int pi = 3.1415926; // 此时并未将 pi 放入只读存储器中
double i=pi;// 此时为 pi 分配内存,以后不再分配
double I = PI // 编译期间进行宏替换,分配内存
double j = pi // 没有分配内存
double J = PI // 再次进行宏替换,又一次分配内存
const 定义常量从汇编的角度来看,只是给出了相应的内存地址,而不是像#define一样给出的是立即数,所以const定义的常量在程序运行过程中只有一份复制品,而#define定义的常量在内存中有若干各复制品。
(7)为了提高程序的效率。编译器通常不为普通的const常量分配存储空间,而是将他们保存在符号表中,这使得它成为一个编译期间常量,没有了存储与内存的操作,使得它的效率也很高。
引申1:什么情况下需要使用const关键字?
(1)修饰一般常量。
(2)修饰常数组。定义或说明一个常数组可以采用如下格式:
int const a[8] = {1, 2, 3, 4, 5, 6, 7, 8}
const int a[8] = {1, 2, 3, 4, 5, 6, 7, 8}
(3)修饰常量对象。常量对象是指对象常量
class A;
const A a;
A const a;
定义常量对象时,同样要进行初始化,并且该对象不能再被更新。
(4)修饰指针常量
const int* A; // const 修饰指向的对象, A可变,A指向的对象不可变。
int const *A // cconst修饰指向对的对象, A可变,A指向的对象不可变
int* const A// 修饰指针A, A不可变, A指向的对象可变。
const int* const A; // 指针A和A指向的对象都不可变
(5) 修饰常引用。使用 const 修饰符也可以说明引用,被说明的引用为常引用,该引用所引用的对象不能被更新。其定义格式如下:
const double &v;
(6)修饰函数的常参数。const 修饰符也可以修饰函数的传递参数,告诉编译器此参数在函数体内无法改变,从而防止了使用者一些无意或错误的修改。
(7)修饰函数的返回值。例如
函数返回值为 const 只有用在函数返回为引用的情况。函数返回值引用常量表示不能将函数调用表达式作为左值使用。例如前面讲的返回引用的函数int & min ( int &i, int &j); 可以对函数调用进行赋值,因为它返回的是左值: min ( a , b )=4;但是,如果对函数的返回值限定为 const 的:const int & min ( int & i, int &j );那么,就不能对 min ( a, b ) 调用进行赋值了。
(8)修饰类的成员函数。Const修饰符也可以修饰类的成员函数,格式如下:
class ClassName {
public:
int fun () const;
}这样在函数fun中不能修改类或对象的属性
(9)在另一连接文件中引用const常量。使用方式必须使用extern关键字
extern const int i; // 正确
extern const int j = 10; // 错误,常量不可以被再次赋值。另外还要注意常量必须初始化。
引申2:什么是常引用?
常引用也称之为const引用。之所以引入常引用,是为了避免在使用引用变量时无意修改了变量的值,从而引起程序的错误,常引用主要用于定义一个普通变量的只读属性的别名。
常引用的用途:
(1)用作普通变量的只读属性的别名。通常这个别名只能获得这个变量的值,不能修改这个变量的值。
(2)用于函数的形参。常引用被用作形参,可以确保在函数内不会改变实参的值,所以参数传递时尽量使用常引用类型。
关于引用的初始化,一般要注意以下问题:
当初始化值是一个左值(可以取得地址时,没有任何问题)
而当初始化值不是一个左值时,则只能对一个常引用赋值,而且这个赋值是有一个过程的,首先将值隐示转换到类型T,然后将这个转换结果存放在一个临时对象里,最后用这个临时对象来初始化这个引用变量。
例如如下两种使用方式:
(1)double& dr = 1;
(2)const double& cdr = 1;
第(1)种方法错误,初始化值不是左值,而第(2)种方法正确,其对应的的执行过程如下:
double tmp = double(1);
const double& cdr = tmp;
如果对第(1)种使用方法进行相应的改造,也可以变为合法,例如:
const int ival = 1024;
(1)const int &refVal = itval;
(2)int &ref2 = ival;
(1):合法
(2):非法
原因:因为itval为const常量而ref2并没有申明为常引用。
在使用const引用进行函数调用的时候,需要注意一个问题,
例如如下函数申明:
void bar(string& s);
那么下面的表达式将是非法的。
bar(”hello world“);
原因在 "hello world" 串会产生一个临时对象,而在c++中,临时对象是 const 类型的
因此上面的表达式就是试图将一个const类型的对象转换为非const的类型,这是非法的。引用型参数应该在能被定义为const的情况下,尽量定义为const。