const的用法
数据共享是编程中常常遇到的现象,但随之而来的是数据的保护问题。C++提供了数据的多种保护机制,防止在无意间对数据进行误操作,修改数据。const是一种有效的手段,保证了数据的共享又不会改变数据。本文对const最常见的用法进行了总结和介绍。
1.const和普通变量
在定义变量的前面加上const关键词,就表明这是一个常变量,变量的值不能改变。如:
const int number=0; //因为常量在定义后就不能被修改,所以定义时必须初始化。
const int i, j=0; //error,必须在定义变量i的时候进行初始化
const变量默认为文件的局部变量。在全局作用域里定义的非const变量,在整个程序中都可以访问,即只要在别的文件中对变量做声明,那么别的文件是可以访问这个变量的(非const变量默认是extern)。但是,对于const变量,要使const变量能在别的文件中访问,必须显示的指定它为extern。
int number; //能在其余文件中访问变量number
const int number=0; //不能在其余文件中访问变量number
extern const int number=0; //能在其余文件中访问变量number,并且在访问时只需要对number进行声明即 extern const int number;
2.const和引用
引用是对象的另一个名字,是一种符合类型,用“&”符合定义。引用和变量名都指向同一段内存单元。引用必须与该引用对象同类型,并用同类型进行初始化。非const引用只能绑定到与该引用同类型的非const对象,const引用可以绑定到const和非const对象或常量(常数值)。如:
constint number=0;
constint &refnumber=number; //定义正确,都是const的int类型
int &refnum=number; //错误,refnum为非const引用,number为const变量
int a=0; //定义变量i
const int & ref=0; //绑定到右值
const int & ref1=a; //const绑定到非const变量
3.const和指针
指针本来就是一个难点,再加上const更是在使用时要小心。
const和指针连用,为了使指针为常量指针、指针指向的值为常量或两者都为常量。下面通过例子进行说明。
int a1=3; //non-const data
int*a2 = &a1;//non-const data,non-const pointer
const int* a3 = &a1;//const data,non-const pointer
int const *a4 = &a1;//const data,non-const pointer
上面这两种表达形式相同,表明指针指向的内存单元里的内容为常量,不能改变,而指针的指向的内存地址可以改变,则*a3=0;错误 *a4=0;错误,不能通过指针去引用改变指针指向变量的值
const int *ptr; 说明ptr是指向一个int类型的const对象的指针,const限定了ptr指向的对象类型,并没有限定ptr。即ptr不是const,允许ptr指向另一个const对象,但不能通过ptr修改指向对象的值,如 *ptr=0;
int* const a5 = &a1; //non-const data,const pointer
上面这种情况表明指针为常量,不能更改指针,即指针指向的内存单元地址不能改变,但内存单元里的数值可以改变。如a5++;错误,但*a5=0;正确
int const* const a6 = &a1;//const data,const pointer
const int* const a7 = &a1;//const data,const pointer
这两种情况表明指针和指针指向的内容都为常量,都不能改变。a6和a7首先是一个const指针,指向的内存单元地址不能改变,再次指向的内存单元的值不能改变。
【const修饰指针变量】
(1)只有一个const,如果const位于*左侧(指向const对象的指针),表示指针所指数据是常量,不能通过解引用修改该数据;指针本身是变量,可以指向其他的内存单元。
(2)只有一个const,如果const位于*右侧(const指针),表示指针本身是常量,不能被修改,不能指向其他内存地址;指针所指的数据可以通过解引用修改。
(3)两个const,*左右各一个(指向const对象的const指针),表示指针和指针所指数据都不能修改。
上面三种情况是最常见的const用法,也是后面const与函数、const和对象(类)的基础。
4.const 与函数
(1)const修饰函数
在函数的末尾加上const,表示个函数是一个常函数,表明它不能改变任何一个数据成员。如:void display() const如果这个函数试图改变任何一个数据或,将导致一个编译错误。
(2)const修饰函数参数
函数的参数形式,可以是变量,引用或者指针,const修饰函数参数,参数在函数内不可以改变。传递过来的参数在函数内的约束条件与上面修饰变量、引用和指针类似。如:voiddisplay(cosnt int x, int y),如果在函数体内修改了x,编译器就会报错
(3)const修饰函数返回值
const声明了返回值后,const对返回值起到相应的保护作用。同时接收返回值的变量也必须加const。
①函数返回值采用“值传递方式”,函数把返回值复制到外部临时的存储单元中。如:const int function();
const int a = function (); //接收的变量也要是const的, int a = fun()是错误的
②如果返回值是对象,采用const int& function()能提高效率,返回的是对象的别名。
③如果给以“指针传递”方式的函数返回值加const 修饰,那么函数返回值(即指针)的内容不能被修改。
如:const int * function();
char*str = function ();//编译错误
const char *str = function ();//正确,函数返回值和接收变量str都是const
5.const 与对象
这里说的对象是有类实例化产生的。类一般包括数据成员和成员函数。一个对象所占的空间大小取决于类的数据成员,与成员函数无关。成员函数是存储在对象空间之外的。即,同一个类产生的不同对象,调用同一个成员函数(同一个操作),函数的入口地址相同,只是用用this指针指向不同对象,区别不同对象的数据成员。
(1)常对象
在定义对象前加上const,指定对象为常对象。如:Time是一个定义的类,那么可以有两种方式定义常对象。Time constt1;等价于const Timet2;如果对象被定义为常对象,则通过对象只能调用常成员函数,不能通过对象访问普通成员函数。常对象保证了数据成员为常数据成员,值不能被修改,但成员函数如果没有加const表示非常函数。
(2)常数据成员
前面讲过,常对象的数据成员都是常数据成员。如果我们需要对象的有的数据成员的值可以改变,有的不能改变,我们在可以在类定义的时候对数据成员用const声明为常数据成员。需要注意的是常数据成员只能通过构造函数的参数初始化表进行初始化,不能在成员函数中对其初始化,包括构造函数。
(3)常成员函数
常成员函数依然是函数,所以它们同样遵循前面const和函数的一些规则,这里在叙述一下用const修饰类里的成员函数时需要注意的地方。
在类里定义成员函数时,在函数的末尾加上const,表示个函数是一个常成员函数。如:void display() const。 const修饰的成员函数不能修改任何的成员变量,也不能调用非const成员函数,因为非const成员函数可能会修改成员变量。
const和对象还包括指向对象的常指针、指向常对象的指针变量和对象的常引用,这和前面讲的类似,注意区别就是前面讲的是简单数据类型,这里换成了抽象数据类型——类,所以这里不再赘述。
参考文献:
http://blog.csdn.net/youoran/article/details/8517611
http://blog.csdn.net/Eric_Jo/article/details/4138548
http://www.cnblogs.com/xudong-bupt/p/3509567.html