看到const 关键字C++程序员首先想到的鈳能是const 常量,这可不是良好的条件反射如果只知道用const 定义常量,那么相当于把火药仅用于制作鞭炮const 更大的魅力是它可以修饰函数的参數、返回值,甚至函数的定义体
const 是constant 的缩写,“恒定不变”的意思被const 修饰的东西都受到强制保护,可以预防意外的变动能提高程序的健壮性。所以很多C++程序设计书籍建议:“Use const whenever you need”
(1)const修饰普通变量和指针
const修饰变量,一般有两种写法:
这两种写法在本质上是一样的它的含义昰:const修饰的类型为TYPE的变量value是不可变的。对于一个非指针的类型TYPE无论怎么写,都是一个含义即value值不可变。 例如:
但是对于指针类型的TYPE鈈同的写法会有不同情况:
指针所指向的内容是常量不可变
识别const到底是修饰指针还是指针所指的对象,还有一个较为简便的方法也就是沿着*号划一条线:
如果const位于*的左侧,则const就是用来修饰指针所指向的变量即指针指向为常量;
如果const位于*的右侧,const就是修饰指针本身即指針本身是常量。
const修饰函数参数是它最广泛的一种用途它表示在函数体中不能修改参数的值(包括参数本身的值或者参数其中包含的值):
参數const通常用于参数为指针或引用的情况,若输入参数采用“值传递”方式由于函数将自动产生临时变量用于复制该参数,该参数本就不需偠保护所以不用const修饰。
所以通常只有以下2种形式有意义。
const修饰输入参数:如果输入参数采用“指针传递”那么加const 修饰可以防止意外哋改动该指针,起到保护作用例如StringCopy 函数:
如果输入参数采用“值传递”,由于函数将自动产生临时变量用于复制该参数该输入参数本來就无需保护,所以不要加const 修饰
类型的临时对象用于复制参数a,而临时对象的构造、复制、析构过程都将消耗时间
为了提高效率,可鉯将函数声明改为void Func(A &a)因为“引用传递”仅借用一下参数的别名而已,不需要产生临时对象
&x),以便提高效率完全没有必要,因为内部数據类型的参数不存在构造、析构的过程而复制也非常快,“值传递”和“引用传递”的效率几乎相当
问题是如此的缠绵,我只好将“const &”修饰输入参数的用法总结一下
对于非内部数据类型的输入参数,应该将“值传递”的方式改为“const 引用传递”目的是提高效率。例如將void Func(A a) 改为void Func(const A &a)
对于内部数据类型的输入参数,不要将“值传递”的方式改为“const 引用传递”否则既达不到提高效率的目的,又降低了函数的可悝解性例如void Func(int x) 不应该改为void Func(const int &x)。
如果给以“指针传递”方式的函数返回值加const 修饰那么函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加const 修饰的同类型指针
如下语句将出现编译错误:
如果函数返回值采用“值传递方式”,由于函数会把返回值复制到外部临时的存储单元中加const 修饰没有任何价值。
如果返回值不是内部数据类型将函数A GetA(void) 改写为const A & GetA(void)的确能提高效率。但此时千万千万要小心一定要搞清楚函数究竟是想返回一个对象的“拷贝”还是仅返回“别名”就可以了,否则程序会出错
函数返回值采用“引用传递”的场合并不多,這种方式一般只出现在类的赋值函数中目的是为了实现链式表达。
如果将赋值函数的返回值加const 修饰那么该返回值的内容不允许被改动。上例中语句 a = b = c 仍然正确,但是语句 (a = b) = c 则是非法的
任何不会修改数据成员(即函数中的变量)的函数都应该声明为const 类型。如果在编写const 成员函数時不慎修改了数据成员,或者调用了其它非const 成员函数编译器将指出错误,这无疑会提高程序的健壮性以下程序中,类stack 的成员函数GetCount 仅鼡于计数从逻辑上讲GetCount 应当为const
函数。编译器将指出GetCount 函数中的错误
const 成员函数的声明看起来怪怪的:const 关键字只能放在函数声明的尾部,大概昰因为其它地方都已经被占用了
const数据成员只在某个对象生存期内是常量,而对于整个类而言却是可变的因为类可以创建多个对象,不哃的对象其const数据成员的值可以不同所以不能在类声明中初始化const数据成员,因为类的对象未被创建时编译器不知道const 数据成员的值是什么,例如:
const数据成员的初始化只能在类的构造函数的初始化列表中进行要想建立在整个类中都恒定的常量,可以用类中的枚举常量或者static const变量来实现例如:
枚举常量不会占用对象的存储空间,他们在编译时被全部求值但是枚举常量的隐含数据类型是整数,其最大值有限苴不能表示浮点数。