const 限定符

来源:互联网 发布:淘宝子账号怎么创建 编辑:程序博客网 时间:2024/05/21 11:32
  1. const对象一旦创建其值就不能再改变,所以const对象必须被初始化(很多书上有很多结论是基于此,其实是有一种办法改变const对象的值,下面将会给出这种办法)。
    方法如下:
    “TestConst.h”
class TestConst{public:    TestConst(void);    ~TestConst(void);private:    const int m;};

“TestConst.cpp”

TestConst::TestConst(void)    : m(0){    *((int *)(&m))=5;    cout<<"直接输出m:"<<m<<endl;    const int temp=3;    *((int *)(&temp))=6;    cout<<"temp直接输出结果:"<<temp<<endl;    cout<<"*((int *)(&temp))的输出结果:"<<*((int *)(&temp))<<endl;}

主函数:

int _tmain(int argc, _TCHAR* argv[]){    TestConst tc;    return 0;}

运行结果:
这里写图片描述

a). 当const常量为类成员时(如上例中的m),此时是可以通过取地址,然后改变指针类型进而改变const常量的值(如:((int )(&m))=5;),如图实验结果直接输出m的值为改变后的值5。估计是这种情况下,编译器编译的时候没法用常量的值替换常量成员m,故没有替换。
b). 当const变量非类成员时,通过取常量成员地址,然后改变指针类型进而改变const变量的值(如:((int )(&temp))=6;),然后直接输出const类型的常量(temp)值,发现temp的值还是为原来的3,当输出((int )(&temp))时,结果却为6。这种情况下,编译器在编译时就用3替换了temp,所以改变无效,但可以通过((int *)(&temp))访问改变后的值。

2.与非const类型所能参与的操作相比,const类型的对象能完成其中大部分的操作,但不是所有的操作都适合。主要的限制就是只能再const类型的对象上执行不改变其内容的操作。如:const int 和普通的int都能参与算术运算,也都能转换成布尔值等。
3. 如果利用一个对象去初始化另外一个对象,则它们是不是const都无关紧要:

    int i=2const int ci=i; //i的值别拷贝给了ci    int j=ci;  //ci的值被拷贝给了j

ps: ci的常量特征仅仅再执行改变ci操作时才会发挥作用

4.如果想在一个文件中定义const,而在其他多个文件中申明并使用它。解决的办法是,对于const变量不管是申明还是定义都添加extern关键字,这样只需要定义一次就可以了:

      //file_1.c定义并初始化了一个常量,该常量能被其他文件访问       extern const int bufSize=fcn();       //file_1.h头文件       extern const int bufSize;
    file_1.cpp中extern const int bufSize=fcn();包含了初始值,所以它是一次定义。然而,因为bufSize是一个常量,必须用extern加以限定使其被其它文件使用。    file_1.h头文件中的申明也有extern 做了限定,其作用是指明bufSize并非本文件所独有,它的定义将在别处出现。

ps:如果想在多个文件之间共享const对象,必须在变量的定义之前加extern关键字。

5.const的引用
对常量的引用就是把引用绑定到const对象上,与普通引用不同的是,对常量的引用不能被用作修改它所绑定的对象:

const int ci=2;const int &r1=ci; //正确:引用及其对象都是常量r1=5;   //错误:l-value specifies const object(左值是const对象)int &r2=ci;     //错误:'initializing' : cannot convert from 'const int' to 'int &'

不允许直接为ci赋值,也就不能通过引用去改变ci。因此,对r2的初始化是错误的。假设该初始化合法,则可以通过r2来改变它引用对象的值,显然不正确。
ps:引用的对象是常量还是非常量可以决定其所能参与的操作,却无论如何都不会影响到引用和对象的绑定关系本身。

6.初始化和对const的引用
引用的类型必须与其所引用对象的类型一致,但是有两个例外。
a). 在初始化常量引用时允许用任意表达式作为初始值,只要该表达式的结果能转换成引用的类型即可。尤其,允许为一个常量引用绑定非常量的对象、字面值,甚至是个一般表达式

int i=2;const int &r1=i;const int &r2=2;const int &r3=r1*2;int &r4=r1*2;//'initializing' : cannot convert from 'int' to 'int &'

当一个常量引用被绑定到另外一种类型上时,到底发生了什么?

double dval=3.14;const int &ri=dval;//正确

编译器把上述代码变成如下形式:

double dval=3.14;const int temp=dval;//由双精度生成一个临时的整型常量const int &ri=temp;//让ri绑定这个临时量

如果ri不是常量,就允许对ri赋值,这样就会改变ri所引用对象的值。此时,绑定的对象是一个临时量(所谓临时量对象就是当编译器需要一个空间来暂存表达式的求值结果是临时创建的一个未命名的对象)而非dval。既然让引用dval,就肯定想通过ri改变dval的值,否则干什么要给ri赋值呢?此时非法

double dval=3.14;int &ri=dval;//报错'initializing' : cannot convert from 'double' to 'int &'

b). 对const的引用可能引用一个非const的对象
常量的引用仅对引用可参与的操作做出了限定,对于引用的对象本身是不是常量没有限定。因为对象也可能是个非常量,所以允许通过其他途径改变它的值:

int i=2;int &r1=i;const int &r2=i;  //正确,r2也绑定对象i,但是不允许通过r2修改i的值r1=0;   //r1并非常量,i的值修改为0r2=0;  //报错:l-value specifies const object

ps:不允许通过r2修改i的值,但是可以通过其它方式修改。例如:直接给i赋值。

7.指针和const
与常量引用类似,指向常量的指针不能用于改变其所指对象的值。要想存放常量的地址,只能使用指向常量的指针。
指针的类型必须与其所指对象的类型一直,但是有个例外。
a). 允许令一个指向常量的指针指向一个非常量对象(虽然不能通过此指针改变非常量对象的值)。
const 指针
常量指针必须初始化,而且一旦初始化,则它的值(存放在指针中的地址)就不能再改变了。

int errNumb=0;int *const curErr=&errNumb;   // curErr将一直指向errNumbconst double pi=3.14159;const double *const pip=&pi;   //pip是一个指向常量对象的常量指针(不论是pip所指的对象值还是pip自己存储的那个地址值都不能改变)
int *const curErr=&errNumb;从右往左看,离curErr最近的符号是const,说明curErr本身是一个常量对象,对象的类型由申明符的其余部分确定,常量指针curErr指向的是一个int对象。

指针本身是一个常量并不意味着不能通过指针修改其所指对象的值,能否这样完全依赖于所指对象的类型。

0 0
原创粉丝点击