首先说明一下const在C和C++中的主要用法,被const修饰的东西都受到强制保护,可以预防意外的变动,能提高程序的健壮性。它可以修饰变量、函数的参数、返回值,甚至函数的定义体。
const修饰变量
const修饰变量通常用于定义符号常量。我们过去一般使用宏定义的方式定义符号常量,比如:
#define PI3.1415926
其实我们也可以使用const方式定义符号常量,下面的语句与上面宏定义的方式达到的效果相似。
const double PI3.1415926
那两者有什么区别呢?在使用宏定义的方式时,首先在预处理过程中将源程序中的常量名全部替换成对应的字面常量,然后对替换过的源程序进行编译。相比较之下const方式不涉及预处理过程,它只在编译过程中起作用。因为宏定义方式定义的符号常量没有类型,所以不能进行严格的类型检查,而const则可以,并且有些调试工具可以对const常量进行调试,而不能对宏常量进行调试。但这也不是说宏常量就比const常量差,比如你能够利用const常量实现下面的宏定义功能么?
#ifndefJIANGXIN_H
#defineJIANGXIN_H
#endef
而且由于历史原因,实际上使用宏常量的情况远远大于const常量,特别是在纯C编程环境中。不过在C++编程环境中,我还是推荐你使用const,因为这更加安全。同时时刻记住一句话,const常量作用与编译期,宏常量作用于预编译期,当你遇到一些令人迷惑的问题时想想这句话,或许能够有所收获。
现在举几个例子:
const int m = 0; //其实我们通常把const符号常量叫做const常量,以便和宏常量区分
typedef char * pStr; //新的类型pStr,代表一个指向char的指针类型。
char string[4] = "abc";
const char *p1 = string;//p1是一个指针,指向一个const char类型
p1++; //正确,p1本身不是常量,它指向一个常量
const pStr p2 = string; //p2是一个常量指针,这个指针指向一个char类型变量
p2++; //错误,p2是一个常量指针
char *const p3 = string; //p3同p2相同,是一个常量指针
char const* p4 = string; //p4同p1相同,是一个指向const char的指针,只能用于C中,在C++中只能使用const char *p4 = string;
const修饰函数形参
函数形参主要包括传值型参数,传指针型参数,传引用型参数。
对于传指针和传引用型参数,如果我们怕在该函数中错误的改变实参的值,一般都会加上const来修饰形参。
对于传值型参数,我们一般不会使用const修饰,因为完全没有必要,你是不是用const,都不能改变实参的值,因为传值型形参是在栈中分配的,函数调用之后一定会销毁。例如:void Fun(int n)和void Fun(const int n)没有任何区别,而且还是代码更加晦涩,所以不推荐。但是有一种情况需要考虑,如果你需要传递一个比较复杂的类类型,但是你又不需要改变该类的对象,这时你可以将传值改为传指针或者引用,同时用const修饰。这样的话就避免了构造临时对象的开销。比如加入A是一个很复杂的类类型,这是使用void Fun(const A &a)要比void Fun(A a)效率更高。
用const修饰函数的返回值
函数的返回值与形参类似,也包括返回值类型,返回指针类型,返回引用类型。
对于返回值类型为指针或者引用的情况,如果我们不希望其被修改,可以使用const对返回值进行限定。此时该返回值const修饰的同类型const指针(返回值为指针)或者同类型的const变量(返回值为引用,且该值为基本类型或者定义了拷贝构造函数、拷贝赋值运算符的类型)。如对于:
const char * Fun(void);
如下语句将出现编译错误:
char *str = Fun();//cannotconvert from 'const char *' to 'char *';
正确的用法是:
const char *str= Fun();
如果返回值类型为值类型,由于函数会把返回值复制到外部函数的存储单元中,加const修饰没有任何价值,所以不要把函数int Fun(void) 写成const int Fun(void)。但是在某些情况下将值类型改为引用类型或者指针类型可以提高效率,可用不用const就看你要不要改变它们了。
const修饰成员函数
const关键字可以放在非静态成员函数声明的尾部,表示该函数不修改对象中的成员变量的值。注意const只能修饰非静态成员函数,不能修饰普通函数,无论是C还是C++。
有些人可能会疑惑为什么纯虚函数后面为什么一般都写const,其实如前所述,函数后面的const只是提示以后维护代码的人,这个函数里面没有改变变量的值。所以,只要是没有改变变量值的函数,就在后面写个const,纯虚函数当然没有改变某个变量的值,所以习惯上就加了const,成员函数用不用const关键在于这成员函数是不是要修改对象的数据成员。而与纯虚函数没什么关系。