- 使用目的及优点:
(1)如果在程序中多个地方使用同一个常量,则需要修改这个常量时,不用每一个使用的地方都修改,只需在定义的地方修改即可。
比如:在头文件中声明一个表明一年中月份数的符号常量:
const int Month = 12;
这样,在以后程序中用到12这个月份数的时候都可以用Month来代替,假如项目需要月份数变为13了,那么不需要一个地方一个地方的去将12改为13,只需要修改上面语句为:const int Month = 13;即可。
(2)使用常量声明便于程序员理解和阅读常量的意义。比如,上例在程序中看到12并不知道代表什么意义,但是看到Month更好理解代表月份数。
(3)在C语言中有一种通过预处理器方法定义符号常量(#define ) ,C++中const的方法要比define更好。首先,const能够明确指定类型;其次,可以使用C++的作用域规则将定义限定在特定的函数或文件中;第三,可以将const用于更复杂的类型,如数组和结构。如果你以前更熟悉c语言中用#define来定义常量,那么以后请不要这样了,要用const来定义常量。
2、const关键字说明
常类型是指使用类型修饰符const说明的类型,常类型的变量或对象的值不允许被修改或更新,不管出现在任何上下文都是为了这个目的而服务的。
3、const使用方法
(1)定义const对象
const修饰符可以将对象转变为常数对象,意思就是说const修饰的变量的值在程序的任意位置都不允许再被修改,就如同常数一样使用。任何修改该变量的尝试都会导致编译失败。
比如:const int bufferSize = 512;
BufferSize = 10; //错误,不允许对常量赋值
因为常量在定义以后不允许被修改,所以必须在定义时进行初始化。
Const std::string hi = “hello”;
Const int i, j=0; //错误,必须对i赋值初始化
(2)const对象作用域
在全局作用域里定义非const变量时,在整个程序中都可以访问这个变量,我们可以把一个非const变量定义在一个文件中,假设已经做了额外的声明,就可以在另外的文件中使用这个变量。
比如://文件1中 file1.cpp
int count; //定义一个非const变量
//文件2 file2.cpp
extern int count; //在另一个文件中额外声明后就可以
++count; //使用
与此不同,在全局作用域中声明的const变量,是定义该对象的文件的局部变量,不允许其他文件访问。除非在定义时指定其为extern,才可以在另外文件中访问此常变量。
比如://文件1 file1.c
extern const int bufSize = fun(); //使用extern修饰后就可以在其他文件中访问了
//文件2 file2.c
extern cons tint bufSize;
for(int i=0;i!=bufSize;i++)
{}
(注解:非const变量默认为extern,要使const变量能够被其他文件访问,必须显式的指定为extern)
(3)定义const引用
引用,顾名思义是某一个变量或者对象的别名,对引用的操作与对其绑定的变量或者对象的操作完全等价。
const引用就是指向const对象的别名,所以对const引用的操作就相当于对它所指向的const对象的操作。所以,const对象不允许赋值,那么const引用也不允许赋值。
比如:const int ival = 1024;
const int &refVal = ival; //ival为const对象,refVal
//为其引用
&refVal = 512; //错误,不允许对const引用赋值
同理,int &ref2 = ival; 也是错误的,因为ival是const变量,不允许修改其值,而ref2是非常量,允许更改其值,如果引用的话就矛盾了,所以这也是不合法的,const引用只允许指向const对象或变量。
(4)定义const的动态数组
如果我们在自由存储区中定义了存储const对象的数组,那么必须在定义的时候对数组进行初始化,因为数组元素都是const对象,不允许赋值。
比如: const int *pci_bad = new const int[100]; //错误
const int *pci_bad = new const int[100]();
//正确,调用初始化函数进行初始化
(5)指针与const限定符的关系
const和指针的结合应用情况主要有以下几种:
(5.1)指向 常量(const对象) 的指针
形如:const double *cptr;
这个语句的意思是这样的:定义了一个指针cptr,这个指针指向一个double类型的const对象(常量)。注意:此处cptr这个指针本身并不是const常量, 这个语句只是表示指向的对象是const常量,所以可以给这个指针赋值,但是不能通过cptr修改其所指向对象的值。
但是,因为其所指向的对象必须是const常量,所以不允许通过指针来修改其指向的对象值。
比如:*cptr = 42; //是错误的,其指向的对象是常量,不允许赋值
不能使用非const指针保存const对象的地址。
比如:const double pi = 3.14;
Double *cptr = π //错误
Const double *cptr = π //正确
特别注意:const double *cptr定义的时候说表示指向一个const对象,其实这个指针也可以指向一个非const对象,只是不允许通过这个指针改变对象的值。
比如:double dval = 3.14;
Cptr = &dval; //也是对的,重点在于不允许通过*cptr = 43;这样的语句来改变对象的值。
(5.2)常指针(const指针)
常指针(const指针)——本身的值不能被修改。
语句如下: int errNumb = 0;
Int *const curErr = &errNumb; //curErr是一个//const指针
这个语句从左往右读作:指向int类型对象的const指针。
同理,上面提到的const double *cptr读作:指向const double类型对象的指针。
与其他const量一样,const指针的值不能被修改,这意味着不能使curErr指向其他对象。Const指针也必须在定义的时候初始化。
(5.3)指向常量的常指针(指向const对象的const指针)
比如:const double pi = 3.14159;
const double *const pi_psr = π
(6)函数和const限定符的关系
(6.1)类中的const成员函数
格式如下:int getCount(void) const;
注意,在实现中也要有const:
Int Stack:: getCount(void) const
{
}
说明:在一个类中,const成员函数不允许修改这个类中的成员变量或者调用其他非const类型的成员函数,编译器会报错,这有利于提高程序的健壮性。所以,在类中,任何不会修改数据成员的函数都应该定义为常函数。
另外,只有常成员函数才有资格操作常量或常对象,没有const关键字说明的成员函数不能用来操作常对象。
其次,const 是定义为const函数的组成部分,所以可以用来函数重载。
(6.2)const 修饰函数返回值
语句形如: const int fun1();
这种用法跟const修饰变量或者修饰指针是相同的,表示返回值必须是一个const类型的值。所以无法给其赋值,因此这种情况其实很少用到。
(6.3)const修饰函数参数
形如:void function(const int Var);
传递过来的参数在函数内不可以修改(其实无意义,因为Var是形参,并不会改变原变量)
形如:void function(const char *Var);
参数指针所指向的对象为常量,不可以变
形如:void function(char * const Var);
指针本身为常量,不可以改变(无意义,指针为形参,不会变)
这样的一个const引用传递和最普通的函数按值传递的效果是一模一样的,他禁止对引用的对象的一切修改,唯一不同的是按值传递会先建立一个类对象的副本, 然后传递过去,而它直接传递地址,所以这种传递比按值传递更有效.