c/c++ const 关键字详解

int32位 posted @ Nov 06, 2013 06:21:33 PM in c/cpp , 2378 阅读
转载请注明:http://krystism.is-programmer.com/若有错误,请多多指正,谢谢!

首先讲讲c语言中const关键字的作用,很多书把const修饰的关键字叫做常量,但我认为还是叫做只读变量恰当点,毕竟它和真正的右值常量还是有区别的,除了只读(即只能定义时初始化,其他任何时候不能再修改)这个限制外,和普通变量没有什么区别。

基本使用方法,就是在变量声明的加上const修饰即可。如const int N = 0;即声明了一个只读变量N。这个N是不允许修改的。

关键在于涉及指针时需要弄清楚const修饰的是指针本身还是修饰指针指向的对象,这点很重要!

可以这样简单记忆,如果const在 * 前面则const修饰的是指针指向的对象,即指向的对象是只读的。如果const 在 *后面则修饰的是指针本身,即该指针变量不可指向其他对象,而指向的对象并不受const约束。如

	int x = 5, y = 6;
	const int *p = &x;
	int * const q = &x;
	// q = &y;
	// *p = 6;
	p = &y;
	*q = 7;

p指针不能修改指向对象的值(注意:只能说不能通过p来修改所指向对象的值,不能说指向的内容不能修改,完全可以通过其他方式修改其值,比如q指针),而q指针可以修改指向对象的值,但本身是一个只读变量,即不能再指向其他对象。另外,注意一点的是,const变量必须在声明时初始化,这和java中的final修饰符不同,final可以声明不进行初始化,可以在任何时候进行初始化。

c++的引用类型也基本类似,看 & 位置决定const修饰的内容。另外注意以下代码:

typedef int* Pointer;
int x = 5;
const Pointer p =  &x;

很容易把const Pointer p = &x, 展开为 const int *p = &x,引起错误! 注意typedef并不是简单的展开,它和宏有本质的区别。上面定义的p应该相对于int * const p = &x; 即p本身是可读变量,而不是其指向的对象不可修改。

const修饰符有什么作用,也许第一反应就是声明一个常量(为什么要声明常量?与宏#define的区别?)。其实更确切地说,const修饰符的功能是为了保护数据安全。

这在函数传参中更容易理解,假如我有一个char *s 字符串, 我要一个查找某个字符的位置的函数find,返回第一次出现该字符的索引,但我不希望由于传入参数后意外的被修改了原来的字符串,关键是这个函数还不一定是我自己写的,有可能是其他人写的。我们可以声明一个函数为 int find(const char *s)来达到这样的目的。 这样我就不用担心我的字符串被恶意修改了。因此:只要是不需要修改原来的内容,则尽量声明为const参数,减少出错率。比如在写qsort的cmp函数时,应该写成int cmp(const void *a, const void *b),因为不希望在比较的时候就把原来的值篡改了。不过一般情况下,const只对指针或者引用参数有效,int foo(const int n)纯属胡闹,因此该函数是传值,每次调用函数时,都会重新创建该函数所有的形参,此时所传递的实参将会初始化对应的形参,普通的非引用类型的参数通过复制对应的实参实现初始化,函数并没有访问调用所传递的实参本身,因此不会修改实参的值,而只是操作实参的一个副本。因此foo函数形参n没有必要const。当然也有时这样使用,比如int op(const int *a, const int n),a表示一个动态数组,n表示数组大小,我不希望在函数体内意外的修改了n的值,因此声明n为const形参是有用的。另外需要注意:如果是在c++中,应该尽量将不需要修改的参数定义为const引用而不应该使用传值的方法!这样能够避免复制实参,减少开销。虽然op(string s1) 和 op(const string &s1)都不会修改s1,但前者需要复制s1,而后者不需要,如果一个类型的复制代价很大时,这效率更明显!

另外需要注意的是const 指针和非const指针、const引用和非const引用是可以重载的,即int foo(const int *x) 和 int foo(int *x)可以重载,int foo(const int &x) 和 foo(int &x)可以重载,所以说重载与否只看参数类型和个数是不确切的,还需要考虑是否const指针或者引用。int foo(const int &x)可以传入右值, 而foo(int &x)不可以传入右值,因为右值是不可修改的。(注意c++11标准中右值引用 && 可以修改右值,因此int foo(int &&x)可以传入右值). 在决定调用哪个版本时,由传入的参数是否const决定!

在c++类中可以声明const成员函数,即 int foo() const {} ,这样声明说明这个函数不能修改对象成员,即this指针是const的,但注意,const成员函数仍然可以修改mutable修饰的数据成员!

总结一下:const的最主要功能是保护数据, 另外使用const引用还能提高函数运行效率,减少复制实参开销!

转载请注明:http://krystism.is-programmer.com/若有错误,请多多指正,谢谢!
  • 无匹配
  • 无匹配

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter