




已阅读5页,还剩23页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1. const的用法:看到const 关键字,C+程序员首先想到的可能是const 常量。这可不是良好的条件反射。如果只知道用const 定义常量,那么相当于把火药仅用于制作鞭炮。const 更大的魅力是它可以修饰函数的参数、返回值,甚至函数的定义体。 const 是constant 的缩写,“恒定不变”的意思。被const 修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。所以很多C+程序设计书籍建议:“Use const whenever you need”。 1. 用const 修饰函数的参数 如果参数作输出用,不论它是什么数据类型,也不论它采用“指针传递”还是“引用传递”,都不能加const 修饰,否则该参数将失去输出功能。const 只能修饰输入参数: 如果输入参数采用“指针传递”,那么加const 修饰可以防止意外地改动该指针,起到保护作用。 例如StringCopy 函数: void StringCopy(char *strDestination, const char *strSource); 其中strSource 是输入参数,strDestination 是输出参数。给strSource 加上const修饰后,如果函数体内的语句试图改动strSource 的内容,编译器将指出错误。 如果输入参数采用“值传递”,由于函数将自动产生临时变量用于复制该参数,该输入参数本来就无需保护,所以不要加const 修饰。 例如不要将函数void Func1(int x) 写成void Func1(const int x)。同理不要将函数void Func2(A a) 写成void Func2(const A a)。其中A 为用户自定义的数据类型。 对于非内部数据类型的参数而言,象void Func(A a) 这样声明的函数注定效率比较底。因为函数体内将产生A 类型的临时对象用于复制参数a,而临时对象的构造、复制、析构过程都将消耗时间。 为了提高效率,可以将函数声明改为void Func(A &a),因为“引用传递”仅借用一下参数的别名而已,不需要产生临时对象。但是函数void Func(A & a) 存在一个缺点: “引用传递”有可能改变参数a,这是我们不期望的。解决这个问题很容易,加const修饰即可,因此函数最终成为void Func(const A &a)。 以此类推,是否应将void Func(int x) 改写为void Func(const int &x),以便提高效率?完全没有必要,因为内部数据类型的参数不存在构造、析构的过程,而复制也非常快,“值传递”和“引用传递”的效率几乎相当。 问题是如此的缠绵,我只好将“const &”修饰输入参数的用法总结一下。 对于非内部数据类型的输入参数,应该将“值传递”的方式改为“const 引用传递”,目的是提高效率。例如将void Func(A a) 改为void Func(const A &a)。 对于内部数据类型的输入参数,不要将“值传递”的方式改为“const 引用传递”。否则既达不到提高效率的目的,又降低了函数的可理解性。例如void Func(int x) 不应该改为void Func(const int &x)。 2 .用const 修饰函数的返回值如果给以“指针传递”方式的函数返回值加const 修饰,那么函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加const 修饰的同类型指针。例如函数const char * GetString(void); 如下语句将出现编译错误:char *str = GetString(); 正确的用法是const char *str = GetString(); 如果函数返回值采用“值传递方式”,由于函数会把返回值复制到外部临时的存储单元中,加const 修饰没有任何价值。例如不要把函数int GetInt(void) 写成const int GetInt(void)。同理不要把函数A GetA(void) 写成const A GetA(void),其中A 为用户自定义的数据类型。如果返回值不是内部数据类型,将函数A GetA(void) 改写为const A & GetA(void)的确能提高效率。但此时千万千万要小心,一定要搞清楚函数究竟是想返回一个对象的“拷贝”还是仅返回“别名”就可以了,否则程序会出错。函数返回值采用“引用传递”的场合并不多,这种方式一般只出现在类的赋值函数中,目的是为了实现链式表达。 例如:class A A & operate = (const A & other); / 赋值函数 ; A a, b, c; / a, b, c 为A 的对象a = b = c; / 正常的链式赋值(a = b) = c; / 不正常的链式赋值,但合法如果将赋值函数的返回值加const 修饰,那么该返回值的内容不允许被改动。上例中,语句 a = b = c 仍然正确,但是语句 (a = b) = c 则是非法的。 3. const 成员函数任何不会修改数据成员(即函数中的变量)的函数都应该声明为const 类型。如果在编写const 成员函数时,不慎修改了数据成员,或者调用了其它非const 成员函数,编译器将指出错误,这无疑会提高程序的健壮性。以下程序中,类stack 的成员函数GetCount 仅用于计数,从逻辑上讲GetCount 应当为const 函数。编译器将指出GetCount 函数中的错误。class Stack public:void Push(int elem); int Pop(void); int GetCount(void) const; / const 成员函数private:int m_num; int m_data100; ; int Stack:GetCount(void) const + m_num; / 编译错误,企图修改数据成员m_numPop(); / 编译错误,企图调用非const 函数return m_num; const 成员函数的声明看起来怪怪的:const 关键字只能放在函数声明的尾部,大概是因为其它地方都已经被占用了。关于Const函数的几点规则:a. const对象只能访问const成员函数,而非const对象可以访问任意的成员函数,包括const成员函数.b. const对象的成员是不可修改的,然而const对象通过指针维护的对象却是可以修改的.c. const成员函数不可以修改对象的数据,不管对象是否具有const性质.它在编译时,以是否修改成员数据为依据,进行检查.e. 然而加上mutable修饰符的数据成员,对于任何情况下通过任何手段都可修改,自然此时的const成员函数是可以修改它的为什么使用const?采用符号常量写出的代码更容易维护;指针常常是边读边移动,而不是边写边移动;许多函数参数是只读不写的。const最常见用途是作为数组的界和switch分情况标号(也可以用枚举符代替) 用法1:常量取 代了C中的宏定义,声明时必须进行初始化。const限制了常量的使用方式,并没有描述常量应该如何分配。如果编译器知道了某const的所有使用,它甚至可以不为该const分配空间。最简单的常见情况就是常量的值在编译时已知,而且不需要分配存储。C+ Program Language用const声明的变量虽然增加了分配空间,但是可以保证类型安全。C标准中,const定义的常量是全局的,C+中视声明位置而定。用法2:指针和常量使用指针时涉及到两个对象:该指针本身和被它所指的对象。将一个指针的声明用const“预先固定”将使那个对象而不是使这个指针成为常量。要将指针本身而不是被指对象声明为常量,必须使用声明运算符*const。所以出现在 * 之前的const是作为基础类型的一部分:char *const cp; /到char的const指针char const *pc1; /到const char的指针const char *pc2; /到const char的指针(后两个声明是等同的)从右向左读的记忆方式:cp is a const pointer to char.pc2 is a pointer to const char.用法3:const修饰函数传入参数将函数传入参数声明为const,以指明使用这种参数仅仅是为了效率的原因,而不是想让调用函数能够修改对象的值。同理,将指针参数声明为const,函数将不修改由这个参数所指的对象。通常修饰指针参数和引用参数:void Fun( const A *in); /修饰指针型传入参数void Fun(const A &in); /修饰引用型传入参数用法4:修饰函数返回值可以阻止用户修改返回值。返回值也要相应的付给一个常量或常指针。用法5:const修饰成员函数const对象只能访问const成员函数,而非const对象可以访问任意的成员函数,包括const成员函数;const对象的成员是不能修改的,而通过指针维护的对象确实可以修改的;const成员函数不可以修改对象的数据,不管对象是否具有const性质。编译时以是否修改成员数据为依据进行检查。Const 深度解析我们也许学习过const的使用,但是对于const的细致的技术细节却不一定掌握。const的用法在许多的教材上只是简单的介绍,在这里我们对 const进行细致的概念以及用法剖析。const 是由c+采用,并加进标准c中,但是他们的意义完全不同,在旧版本(标准前)的c中,如果想建立一个常量,必须使用预处理器:#define PI 3.14159此后无论在何处使用PI,都会被预处理器以3.14159替代。编译器不对PI进行类型检查,也就是说可以不受限制的建立宏并用它来替代值,如果使用不慎,很可能由预处理引入错误,这些错误往往很难发现。我们也不能得到PI的地址(即不能向PI传递指针和引用)。c+引入了命名常量的概念,命名常量就像变量一样,只是它的值不能改变,如果试图改变一个const 对象,编译器将会产生错误。 const 和正常变量一样有作用域,所以函数内部的const也不会影响程序的其余部分。在c+中const可以取代预处理器#define来进行值替代, const有安全的类型检查,所以不用担心会像预处理器一样引入错误。在通常的情况下const同预处理器#define一样只是将所赋值保存入编译器的符号表中(符号表仅仅在编译时存在,在编译过程中编译器将程序中的名字与之在符号表中定义的数值作简单的替换),在使用的时候进行值替换,并不为const创建存储空间。我们将const的定义放进头文件里,这样通过包含头文件,可以把const定义单独放在一个地方并把它分配给一个编译单元,const默认为内部连接(内部连接意味着只对正在编译的文件创建存储空间,别的文件可以使用相同的标示符和全局变量,编译器不会发现冲突,外部连接意味着为所有被编译过的文件创建一片单独的存储空间,一般全局变量和函数名的外部连接通过extern声明,可以通过其他的文件访问)也就是说const仅能被它所定义过的文件访问,在定义一个const时,必须赋一个值给它,除非用extern做出说明:extern const int a;这表示const的定义在其他的什么地方,这里仅仅是一个声明,但是这样的做法使const使用了外部连接,也就是说上面的extern强制进行了对const的存储空间分配,这样我们就无法再用const作为常量折叠(在可能的情况下,符号常量的值会代替改名字的出现,这个替代过程叫做常量折叠)使用了,即使我们在其他地方定义了const的值,如:extern const int a=3;因为const的值被放入了存储单元,在编译的过程中,编译器不会去读存储单元的内容。如果我们这样做:int ba;编译器就会给我们一个错误信息。想不为const分配存储空间是不可能的,因为对于复杂的结构,例如集合,编译器不会复杂到将集合保存到它的符号表中,所以必须分配内存空间,这就意味着“这是一块不能改变的存储空间”,当然也就不能在编译期间使用它的值,因为编译器不知道存储的内容:const int i=1,2,3,4;/float fi2; /将得到错误信息,编译器提示不能在数组定义里找到一个常数表达式。因为编译器靠移动栈指针来存储和读取数据。(编译时必须为数组分配内存,但这时数组无法读取const常量的值,所以编译器不知道为数组f分配多大的空间。)也因此,由于无法避免为const分配内存,所以const的定义必须默认为内部连接,否则由于众多的const在多个文件中分配内存,就会引起错误。下面我们看一段简单有效的代码来说明const的常量折叠:#include const int a=3;const int b=a+1;float *f=(float*)&b;char cb+3;void main()const char gc=cin.get();const char c2=gc+3;我们可以看到,a是一个编译器期间的const,b是从a中计算出来的,由于a是一个const,b的计算值来自一个常数表达式,而它自身也是一个编译期间的const,接着下面指针f取得了b的地址,所以迫使编译器给b分配了存储空间,不过即使分配了存储空间,由于编译器已经知道了b的值,所以仍然不妨碍在决定数组c的大小时使用b。在主函数main()里,标识符gc的值在编译期间是不知道的,这也意味着需要存储空间,但是初始化要在定义点进行,而且一旦初始化,其值就不能改变,我们发现c2是由gc计算出来的,它的作用域与其他类型const的作用域是一样的,这是对#define用法的一种改进。在c+引进常量的时候,标准c也引入了const,但是在c中const的意思和在c+中有很大不同,在c中const的意思是“一个不能改变的普通变量”,const常量总是被分配存储空间而且它的名字是全局符即const使用外部连接。于是在c中:const int size=100;char csize;得出一个错误。但是在c中可以这样写:const int size;因为c中的const被默认为外部连接,所以这样做是合理的。在c语言中使用限定符const不是很有用,如果希望在常数表达式里(必须在编译期间被求值)使用一个已命名的值,必须使用预处理器#define。在c+中可以使指针成为const,这很有用,如果以后想在程序代码中改变const这种指针的使用,编译器将给出通知,这样大大提高了安全性。在用带有const的指针时,我们有两种选择:const修饰指针指向的对象,或者const修饰指针自己指向的存储空间。如果要使指向的对象不发生改变,则需要这样写:const int *p;这里p是一个指向const int 的指针,它不需要初始化,因为p可以指向任何标识符,它自己并不是一个const,但是它所指的值是不能改变的,同样的,我们可以这样写:int const *p;这两种方法是等同的,依据个人习惯以及编码风格不同,程序员自己决定使用哪一种形式。如果希望使指针成为一个const必须将const标明的部分放在*右边。int a=3;int *const j=&a编译器要求给它一个初始值,这个值在指针的生命期间内不变,也就是说指针始终指向a的地址,不过要改变它地址中的值是可以的:*j+=4;也可以是一个const指针指向一个const对象:const int *j1=&a;int const *j2=&a;这样指针和对象都不能改变,这两种形式同样是等同的。在赋值的的时候需要注意,我们可以将一个非const的对象地址赋给一个const指针,但是不能将一个const对象地址赋给一个非const指针,因为这样可能通过被赋值的指针改变对象的值,当然也可以用类型的强制转换来进行const对象的赋值,但是这样做打破了const提供的安全性。const也被用于限定函数参数和函数的返回值,如果函数参数是按值传递时,即表示变量的初值不会被函数改变,如果函数的返回值为const那么对于内部类型来说按值返回的是否是一个cosnt是无关紧要的,编译器不让它成为一个左值,因为它是一个值而不是一个变量,所以使用const是多余的,例如:const int f()return 1;void main()int a=f();但是当处理用户定义类型的时候,按值返回常量就很有意义了,这时候函数的返回值不能被直接赋值也不能被修改。仅仅是非const返回值能作为一个左值使用,但是这往往失去意义,因为函数返回值在使用时通常保存为一个临时量,临时量被作为左值使用并修改后,编译器将临时量清除。结果丢失了所有的修改。可以用const限定传递或返回一个地址(即一个指针或一个引用):const int * const func(const int *p) static int a=*p;return &a;参数内的const限定指针p指向的数据不能被改变,此后p的值被赋给静态变量a,然后将a的地址返回,这里a是一个静态变量,在函数运行结束后,它的生命期并没有结束,所以可以将它的地址返回。(如果是局部变量,则不可将其值或其地址作为返回值)因为函数返回一个const int* 型,所以函数func的返回值不可以赋给一个非指向const的指针 (因为在赋值的的时候需要注意,我们可以将一个非const的对象地址赋给一个const指针,但是不能将一个const对象地址赋给一个非const指针,因为这样可能通过被赋值的指针改变对象的值),但它同时接受一个const int * const和一个const int *指针,这是因为在函数返回时产生一个const临时指针用以存放a的地址,所以自动产生了这种原始变量不能被改变的约定,于是*右边的const只有当作左值使用时才有意义。const同样运用于类中,但是它的意义又有所不同,我们可以创建const的数据成员,const的成员函数,甚至是const的对象,但是保持类的对象为const比较复杂,所以const对象只能调用const成员函数。const的数据成员在类的每一个对象中分配存储,并且一旦初始化这个值在对象的生命期内是一个常量,因此在类中建立一个const数据成员时,初始化工作必须在构造函数初始化列表中。如果我们希望创建一个有编译期间的常量成员,这就需要在该常量成员的前面使用static限定符,这样所有的对象都仅有一个实例或者利枚举变量:class Xstatic const int size=50;int asize;public:X();const对象只能调用const成员函数,一个普通对象同样可以调用const成员函数,因此,const成员函数更具有一般性,但是成员函数不会默认为const。声明一个const成员函数,需要将const限定符放在函数名的后面:void f (void ) const;当我们运用const成员函数时,遇到需要改变数据成员,可以用mutable进行特别的指定:class Xmutable int i;public:X();void nochange() const;void X:nochange const()i+;mutablemutable 可以用来指出,即使结构或者类变量为const,其某个成员也可以被修改在c+的类中, 如果一个函数被const 修饰,那么它将无法修改其成员变量的,但是如果这个成员变量是被mutable修饰的话,则可以修改。例如struct datachar name30;mutable int accesses;.;const data veep = david;,0,strcpy(,Jimmy);/ not allowedveep.accesses+; / allowedveep 的const限定符禁止程序修改veep的成员,但access成员的mutable说明符表示access不受这种限制const消除了预处理器的值替代的不良影响,并且提供了良好的类型检查形式和安全性,在可能的地方尽可能的使用const对我们的编程有很大的帮助。const类型定义:指明变量或对象的值是不能被更新,引入目的是为了取代预编译指令*常量必须被初始化*cons的作用(1)可以定义const常量例如:constintMax=100;intArrayMax;(2)便于进行类型检查例如:voidf(constinti).编译器就会知道i是一个常量,不允许修改;(3)可以保护被修饰的东西,防止意外的修改,增强程序的健壮性。还是上面的例子,如果在函数体内修改了i,编译器就会报错;例如:voidf(constinti)i=10;/error!(5)为函数重载提供了一个参考。classA.voidf(inti).file:/一个函数voidf(inti)const.file:/上一个函数的重载.;(6)可以节省空间,避免不必要的内存分配。例如:#definePI3.14159file:/常量宏constdoulbePi=3.14159;file:/此时并未将Pi放入ROM中,而是记录在常量表中。 在通常的情况下const同预处理器#define一样只是将所赋值保存入编译器的符号表中(符号表仅仅在编译时存在,在编译过程中编译器将程序中的名字与之在符号表中定义的数值作简单的替换),在使用的时候进行值替换,并不为const创建存储空间。.doublei=Pi;file:/此时为Pi分配内存,以后不再分配!doubleI=PI;file:/编译期间进行宏替换,分配内存doublej=Pi;file:/没有内存分配doubleJ=PI;file:/再进行宏替换,又一次分配内存!const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干个拷贝。(7)提高了效率。编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,这使得它成为一个编译期间的常量,没有了存储与读内存的操作,使得它的效率也很高。使用const(1)修饰一般常量,常数组,常对象修饰符const可以用在类型说明符前,也可以用在类型说明符后。例如:intconstx=2;或constintx=2;intconsta5=1,2,3,4,5;或constinta5=1,2,3,4,5;classA;constAa;或Aconsta;(2)修饰指针constint*A;或intconst*A;/const修饰指向的对象,A可变,A指向的对象不可变int*constA;/const修饰指针A,A不可变,A指向的对象可变constint*constA;/指针A和A指向的对象都不可变(3)修饰引用constdouble&v;该引用所引用的对象不能被更新(4)修饰函数的返回值:const修饰符也可以修饰函数的返回值,是返回值不可被改变,格式如下:constintFun1();constMyClassFun2();(5)修饰类的成员函数:const修饰符也可以修饰类的成员函数,格式如下:classClassNamepublic:intFun()const;.;这样,在调用函数Fun时就不能修改类里面的数据(6)在另一连接文件中引用const常量externconstinti;/正确的引用externconstintj=10;/错误!常量不可以被再次赋值*放在类内部的常量有什么限制?classAprivate:constintc3=7;/err const成员只能在定义对象的时候初始化staticintc4=7;/err,静态数员成员只能在外部初始化staticconstfloatc5=7;/err.;初始化类内部的常量1初始化列表:classApublic:A(inti=0):test(i)private:constinti;;2外部初始化,例如:classApublic:A()private:staticconstinti;;constintA:i=3;C+ const 用法总结#include void func(const int* p, int n);const char * getStr();class CAprivate:int _nA;public:CA(int a):_nA(a)inline int getA() const /_nA+; /error C2166: l 值指定常数对象 return _nA;inline void setA(int a) _nA = a;int main(void)using namespace std;/=/ 1.const修饰变量使其成为常量/= cout-const修饰变量使其成为常量:endl; const int a = 5; couta = aendl; /a = 3; /error C2166: l 值指定常数对象 /int * pa = &a; /error C2440: “初始化” : 无法从“const int *_w64 ”转换为“int *” /int * const pa = &a; /error C2440: “初始化” : 无法从“const int *_w64 ”转换为“int *const ” const int * pa1 = &a; int const * pa2 = &a; cout*pa1 = *pa1endl; cout*pa2 = *pa2endl; /*pa1 = 3; /error C2166: l 值指定常数对象/=/ 2.const修饰指针的几种形式/=cout-const修饰指针的几种形式:endl;/第一种,常量指针,指针是常量,不能修改指向 int a1 = 3; int a2 = 4; int * const pa = &a1; /pa = &a2; /error C2166: l 值指定常数对象 *pa = 5; couta1 = a1endl;/第二种,指向常量的指针,不能通过此指针修改指向的变量的值 int a = 3; const int * pa1 = &a; int const * pa2 = &a; /*pa1 = 5; /error C2166: l 值指定常数对象 a = 5; couta = aendl; const int A = 3; const int *pA = &A; /*pA = 5; /error C2166: l 值指定常数对象 /A = 5; /error C2166: l 值指定常数对象/第三种,指向常量的常量指针,既不能修改指向,也不能修改指向变量的值 int a1 = 3; int a2 = 4; const int * const pa = &a1; /pa = &a2; /error C2166: l 值指定常数对象 /*pa = 5; /error C2166: l 值指定常数对象/=/ 3.const修饰函数参数/=cout-const修饰函数参数:endl;/const一般用于修饰指针或引用类型的函数参数,以避免在函数内部修改其指向的值,/不要用于修饰值传递类型的参数,这样做没有意义。 int a = 3; func(&a, 5);/=/ 4.const修饰函数返回值/=cout-const修饰函数返回值:endl;/返回值为const的指针只能赋值给同类型的const指针 /char * p = getStr(); /error C2440: “初始化” : 无法从“const char *”转换为“char *” 转换丢失限定符 const char * p = getStr(); coutpendl;/=/ 5.const修饰类成员函数/=cout-const修饰类成员函数:endl;/在const修饰的类成员函数内部,不能修改类成员变量的值CA a(1);couta.getA()endl;cin.get();return 0;void func(const int * p, int n)using namespace std;cout*p = *pendl;coutn = nendl;/*p = n; /error C2166: l 值指定常数对象const char* getStr()return hello;面向对象是C+的重要特性. 但是c+在c的基础上新增加的几点优化也是很耀眼的就const直接可以取代c中的#define,以下几点很重要,学不好后果也也很严重const1. 限定符声明变量只能被读 const int i=5; int j=0; . i=j; /非法,导致编译错误 j=i; /合法2. 必须初始化 const int i=5; /合法 const int j; /非法,导致编译错误3. 在另一连接文件中引用const常量 extern const int i; /合法 extern const int j=10; /非法,常量不可以被再次赋值4. 便于进行类型检查 用const方法可以使编译器对处理内容有更多了解。 #define I=10 const long &i=10; /*dapingguo提醒:由于编译器的优化,使 得在const long i=10; 时i不被分配内存,而是已10直接代入 以后的引用中,以致在以后的代码中没有错误,为达到说教效 果,特别地用&i明确地给出了i的内存分配。不过一旦你关闭所 有优化措施,即使const long i=10;也会引起后面的编译错误。*/ char h=I; /没有错 char h=i; /编译警告,可能由于数的截短带来错误赋值。5. 可以避免不必要的内存分配 #define STRING abcdefghijklmnn const char string=abcdefghijklmn; . printf(STRING); /为STRING分配了第一次内存 printf(string); /为string一次分配了内存,以后不再分配 . printf(STRING); /为STRING分配了第二次内存 printf(string); . 由于const定义常量从汇编的角度来看,只是给出了对应的内存地址, 而不是象#define一样给出的是立即数,所以,const定义的常量在 程序运行过程中只有一份拷贝,而#define定义的常量在内存中有 若干个拷贝。6. 可以通过函数对常量进行初始化 int value(); const int i=value(); dapingguo说:假定对ROM编写程序时,由于目标代码的不可改写, 本语句将会无效,不过可以变通一下: const int &i=value(); 只要令i的地址处于ROM之外,即可实现:i通过函数初始化,而其 值有不会被修改。7. 是不是const的常量值一定不可以被修改呢? 观察以下一段代码: const int i=0; int *p=(int*)&i; p=100; 通过强制类型转换,将地址赋给变量,再作修改即可以改变const常量值。8. 请分清数值常量和指针常量,以下声明颇为玩味: int ii=0; const int i=0; /i是常量,i的值不会被修改 const int *p1i=&i; /指针p1i所指内容是常量,可以不初始化 int * const p2i=ⅈ /指针p2i是常量,所指内容可修改 const int * const p3i=&i; /指针p3i是常量,所指内容也是常量 p1i=ⅈ /合法 *p2i=100; /合法 关于C+中的const关键字的用法非常灵活,而使用const将大大改善程序的健壮性,参考了康建东兄的const使用详解一文,对其中进行了一些补充,写下了本文。1. const常量,如const int max = 100; 优点:const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换时可能会产生意料不到的错误(边际效应)2. const 修饰类的数据成员。如:class A const int size; const数据成员只在某个对象生存期内是常量,而对于整个类而言却是可变的。因为类可以创建多个对象,不同的对象其const数据成员的值可以不同。所以不能在类声明中初始化const数据成员,因为类的对象未被创建时,编译器不知道const 数据成员的值是什么。如class Aconst int size = 100; /错误int arraysize; /错误,未知的sizeconst数据成员的初始化只能在类的构造函数的初始化表中进行。要想建立在整个类中都恒定的常量,应该用类中的枚举常量来实现。如class Aenum size1=100, size2 = 200 ;int array1size1;int array2size2; 枚举常量不会占用对象的存储空间,他们在编译时被全部求值。但是枚举常量的隐含数据类型是整数,其最大值有限,且不能表示浮点数。3.const修饰指针的情况,见下式:int b = 500; const int* a = & 1 int const *a = & 2 int* const a = & 3 const int* const a = & 4 如果你能区分出上述四种情况,那么,恭喜你,你已经迈出了可喜的一步。不知道,也没关系,我们可以参考Effective c+Item21上的做法,如果const位于星号的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;如果const位于星号的右侧,const就是修饰指针本身,即指针本身是常量。因此,1和2的情况相同,都是指针所指向的内容为常量(const放在变量声明符的位置无关),这种情况下不允许对内容进行更改操作,如不能*a = 3 ;3为指针本身是常量,而指针所指向的内容不是常量,这种情况下不能对指针本身进行更改操作,如a+是错误的;4为指针本身和指向的内容均为常量。 4.const的初始化 先看一下const变量初始化的情况 1) 非指针const常量初始化的情况:A b; / A为前面自定义的类类型const A a = b; 2) 指针const常量初始化的情况:A* d = new A(); const A* c = d; 或者:const A* c = new A(); 3)引用const常量初始化
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- GB/T 46213-2025废旧粘结钕铁硼磁体再制造技术规范
- 化工传递安全正能量课件
- 养护公路安全培训内容记录课件
- 钢管外架承包协议书与钢管外架租赁承包合同8篇
- 冒号的用法及举例课件
- 初级安全培训课件
- 内镜在异物取出术课件
- 俱乐部商业思维营销方案(3篇)
- 货找人型营销方案(3篇)
- 化学实验教师安全培训课件
- 华为信息安全管理培训课件
- 诗经整本书阅读课件
- (2025年标准)预售小麦协议书
- 2025年院感测试题及答案
- 养生店国庆节活动方案
- GB/T 33467-2016全自动吹瓶灌装旋盖一体机通用技术要求
- GB/T 20481-2006气象干旱等级
- 2023年石家庄水务投资集团有限责任公司招聘笔试模拟试题及答案解析
- 2020牛津译林版高中英语新教材选修第一册全册课文翻译及单词表
- 我国运动员在奥林匹克运动会取得的辉煌成绩课件
- 专升本高等数学的讲义80页PPT课件
评论
0/150
提交评论