和记娱乐


网站导航

联系我们

和记娱乐

联系人: 

电 话:021-64057486

公司网址:http://www.happy123456789.com

   址:成都市松江区漕河泾松江新兴产业园区研展路丰产支路55号B座803室

邮编:201165


通信科技

您的当前位置: 和记娱乐主页 > 通信科技 >

C++中 const的用法 较详细

发布日期:2019-11-24 09:29 来源:和记h88 发布人:和记娱乐 点击:

  关于C++中的const关键字的用法非常灵活,而使用const将大大改善程序的健壮性,参考了康建东兄的const使用详解一文,对其中进行了一些补充,写下了本文。

  优点:const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换时可能会产生意料不到的错误(边际效应)

  const 数据只在某个对象期内是常量,而对于整个类而言却是可变的。因为类可以创建多个对象,不同的对象其const数据的值可以不同。所以不能在类 声明中初始化const数据,因为类的对象未被创建时,编译器不知道const 数据的值是什么。如

  const数据的初始化只能在类的构造函数的初始化表中进行。要想建立在整个类中都恒定的常量,应该用类中的枚举常量来实现。如

  枚举常量不会占用对象的存储空间,他们在编译时被全部求值。但是枚举常量的隐含数据类型是整数,其最大值有限,且不能表示浮点数。

  如 果你能区分出上述四种情况,那么,恭喜你,你已经迈出了可喜的一步。不知道,也没关系,我们可以参考《Effective c++》Item21上的做法,如果const位于星号的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;如果const位于星号的 右侧,const就是修饰指针本身,即指针本身是常量。因此,[1]和[2]的情况相同,都是指针所指向的内容为常量(const放在变量声明符的无 关),这种情况下不允许对内容进行更改操作,如不能*a = 3 ;[3]为指针本身是常量,而指针所指向的内容不是常量,这种情况下不能对指针本身进行更改操作,如a++是错误的;[4]为指针本身和指向的内容均为常 量。

  5.    另外const 的一些强大的功能在于它在函数声明中的应用。在一个函数声明中,const 可以修饰函数的返回值,或某个参数;对于函数,还可以修饰是整个函数。有如下几种情况,以下会逐渐的说明用法:A& operator=(const A& a);

  调 用函数的时候,用相应的变量初始化const常量,则在函数体中,按照const所修饰的部分进行常量化,如形参为const A* a,则不能对传递进来的指针的内容进行改变,了原指针所指向的内容;如形参为const A& a,则不能对传递进来的引用对象进行改变,了原对象的属性。

  [注意]:参数const通常用于参数为指针或引用的情况,且只能修饰输入参数;若输入参数采用“值传递”方式,由于函数将自动产生临时变量用于复制该参数,该参数本就不需要,所以不用const修饰。

  [总结]对于非内部数据类型的输入参数,因该将“值传递”的方式改为“const引用传递”,目的是为了提高效率。例如,将void Func(A a)改为void Func(const A &a)

  对于内部数据类型的输入参数,不要将“值传递”的方式改为“const引用传递”。否则既达不到提高效率的目的,又降低了函数的可理解性。例如void Func(int x)不应该改为void Func(const int &x)

  一般用const修饰返回值为对象本身(非引用和指针)的情况多用于二目操作符重载函数并产生新对象的时候。

  1.    一般情况下,函数的返回值为某个对象时,如果将其声明为const时,多用于操作符的重载。通常,不用const修饰函数的返回值类型为某个对象或对 某个对象引用的情况。原因如下:如果返回值为某个对象为const(const A test = A 实例)或某个对象的引用为const(const A& test = A实例) ,则返回值具有const属性,则返回实例只能访问类A中的公有()数据和const函数,并且不允许对其进行赋值操作,这在一般情况下很少 用到。

  2.      如果给采用“指针传递”方式的函数返回值加const修饰,那么函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加const 修饰的同类型指针。如:

  3.    函数返回值采用“引用传递”的场合不多,这种方式一般只出现在类的赙值函数中,目的是为了实现链式表达。如:

  若负值函数的返回值加const修饰,那么该返回值的内容不允许修改,上例中a=b=c依然正确。(a=b)=c就不正确了。

  任何不会修改数据的函数都因该声明为const类型。如果在编写const函数时,不慎修改了数据,或者调用了其他非const函数,编译器将报错,这大大提高了程序的健壮性。如:

  1 这种方法不正确,因为声明指针的目的是为了对其指向的内容进行改变,而声明的指针e指向的是一个常量,所以不正确;

  使用#define来定义常量也是常用方法,但const也可以用来定义常量,在[Effective C++]中使用const代替#define来定义常量,因为const定义的常量具有类型信息,而宏没有,所以使用const定义的常量在进行赋值操作时编译器会进行更严格的类型检查,是类型安全的。

  定义常量有三种方法:宏、const、enum,其中宏应该尽量避免,而const与enum也各有优缺点,最大的区别就是enum只能用于定义整数,而不能定义浮点数;而对于定义逻辑关系较近的一组整数时比较适合使用enum,也可以考虑使用类代替enum(参见[??])。

  常量必须在定义时进行初始化,之后便不能再赋值。说它不能被赋值并不是说常量的值是绝对不会改变的,只是说不能直接赋值,但可以通过指针及强制类型转换、const_cast是可以改变常量的值的。

  之所以使用ci直接输出变量的值时显示其值始终没有改变,但通过指针间接显示出来的值是改变了,而且输出结果的最后一行很奇怪,ci的值与*cpci的值居然不相等,只因为编译器在编译时进行了优化,将代码中的ci直接替换成了5,与宏替换是相同的效果,而指针的值则是实际内存中的值。

  所以,千万不要试图使用指针改变const变量的值,否则程序可能表现出错误的行为,而且查找起来这种错误非常困难。在gcc 4.3.4和visualC++ 2010中均默认打开了对常量的优化选项,目前还没找到关闭该优化的命令行选项,一定不要自作聪明去改const变量的值。

  把const与指针放到一起,很多人便会想到一个绕口令“指针常量与常量指针。“指针常量”即一个指针变量,该变量不能被赋值,而指针指向的内存单元的内容是可以改变的;“常量指针”即一个指向常量的指针,指针变量本身可以赋值,而指针指向的内存单元的内容是不可以被重新赋值的。

  const是修饰类型还是修饰指针,要看const的,放在*前就是修饰数据类型,放到*后就是修饰指针,constchar和charconst是一样的。

  :在不打算修改数据内容的时候都将指针定义成常量指针,不打算指针本身被修改的场合都定义成指针常量。尽可能地多用const,用错了没关系,编译器会提示你的,只要能够编译通过,就不会因为用错const而导致程序逻辑错误,应该说const负作用极小。

  当使用const修饰类变量时便定义了据,它的使用与使用类外定义的常量本质上并没有什么区别,在这里只想指出一点:有网友提到const数据只能被const修饰的函数使用这是没有根据的,是错误的。

  使用const修饰的函数不能修改类的变量,如_port,而且只能调用类对象const函数,但有个例外,就是mutable修饰的变量可以在const修饰的函数中被修改,如_readCount。

  :将所有不改变对象状态的函数都使用const修饰符标识,以提高程序的可读性。其实,头文件就是最好的类接口的说档,越多的提供信息就能使程序的可读性越好,越利于。看到函数的const修饰符,读者便立即明白该函数不会改变程序的状态,这也有利于当程序状态出现异常时的问题定位。

  当const修饰自定义的类对象时,与修饰C++内置类型的变量的思想是一致的,但稍有不同,除了不能被赋值外,还不能调用没有使用const修饰的非静态函数。当const修饰类对象引用、指针时是一样的,因为引用本身与直接使用该变量实质上没有区别,而使用指针只是将.操作符改为了->本质上还是一样的

  const修饰函数的例子是很常见了,表示函数的参数在函数体内不会被意外修改,一般用于修饰输入参数,例如标准库中的字符接函数。str1是输出参数,其内容会被修改,而str2为输入参数,其内容不会修改。

  实际上在说到const用法一开始就提到,const只是一种声明,但并不能,例如strcat函数虽然声明了str2为constchar*型,但并不能内部绝对不会修改str2的内容。但const从语言本身提供了一种编写自描述性代码的方法,只要使用函数与实现函数的双方都达成一致的约定,按照契约编程,我们就可以认为const修饰的类型在函数体内不会被修改,这与const修饰类函数一样,可以提高软件的可读性。

  const可以用于修饰任何类型,只要返回值类型不是void,const就可以用来修饰返回值的类型。但实际上const用于修饰非引用的返回值类型是没有意义的,因为返回值一般都会被赋值给另一个变量,此时用于传递返回值的对象已经被,修饰返回值类型的const的作用也就终结了。

  此处,为了减少构造临时变量,将IP函数返回值定义为引用类型以提高程序运行效率,但为了内部状态不会被客户端代码意外,返回值使用const修饰为常引用。但是,如果对于软件安全性较高的场合,最好不要定义为引用,因为恶意的客户端代码是有可能修改Socket::_ip的值的。

  显然,在实际工程中谁也不会写出这样的代码,这段代码却是的,无疑这给程序员多了一种出错的可能,如果把赋值运算符的返回值定义为常引用,则会减少程序员出错的机会,例如[??]:

      和记娱乐,和记h88,h88平台官网