const用法

C语言中const的用法 

基本解释   

        const是一个C语言的关键字,它限定一个变量不允许被改变。使用const在一定程度上可以提高程序的健壮性,另外,在观看别人代码的时候,清晰理解const所起的作用,对理解对方的程序也有一些帮助。   虽然这听起来很简单,但实际上,const的使用也是c语言中一个比较微妙的地方,微妙在何处呢?请看下面几个问题。    

    问题:const变量 & 常量   

    为什么我象下面的例子一样用一个const变量来初始化数组,ANSI C的编译器会报告一个错误呢?   const int n = 5;   int a[n];      答案与分析

    1)、这个问题讨论的是“常量”与“只读变量”的区别。常量肯定是只读的,例如5 abc”,等,肯定是只读的,因为程序中根本没有地方存放它的值,当然也就不能够去修改它。而“只读变量”则是在内存中开辟一个地方来存放它的值,只不过这个值由编译器限定不允许被修改。C语言关键字const就是用来限定一个变量不允许被改变的修饰符(Qualifier)。上述代码中变量n被修饰为只读变量,可惜再怎么修饰也不是常量。而ANSI C规定数组定义时维度必须是“常量”,“只读变量”也是不可以的。 

    2)、注意:在ANSI C中,这种写法是错误的,因为数组的大小应该是个常量,而const int n,n只是一个变量(常量 != 不可变的变量,但在标准C++中,这样定义的是一个常量,这种写法是对的),实际上,根据编译过程及内存分配来看,这种用法本来就应该是合理的,只是 ANSI C对数组的规定限制了它。     3)、那么,在ANSI C 语言中用什么来定义常量呢?答案是enum类型和#define宏,这两个都可以用来定义常量。     

  问题:const变量 & const 限定的内容 

  下面的代码编译器会报一个错误,请问,哪一个语句是错误的呢?   typedef char * pStr;   char string[4] = "abc";   const char *p1 = string;   const pStr p2 = string;   p1++;   p2++;  

    答案与分析:     问题出在p2++上。 

    1)const使用的基本形式: const char m; 限定m不可变。 

    2)、替换1式中的m, const char *pm; 限定*pm不可变,当然pm是可变的,因此问题中p1++是对的。 

    3)、替换1char, const newType m; 限定m不可变,问题中的charptr就是一种新类型,因此问题中p2不可变,p2++是错误的。  

    问题:const变量 & 字符串常量     请问下面的代码有什么问题?   char *p = "i'm hungry!";   p[0]= 'I';  

    答案与分析: 

    上面的代码可能会造成内存的非法写操作。分析如下, i'm hungry”实质上是字符串常量,而常量往往被编译器放在只读的内存区,不可写。p初始指向这个只读的内存区,而p[0] = 'I'则企图去写这个地方,编译器当然不会答应。    

    问题:const变量 & 字符串常量

    请问char a[3] = "abc" 合法吗?使用它有什么隐患?      答案与分析: 

    在标准C中这是合法的,但是它的生存环境非常狭小;它定义一个大小为3的数组,初始化为“abc”。注意,它没有通常的字符串终止符'\0',因此这个数组只是看起来像C语言中的字符串,实质上却不是,因此所有对字符串进行处理的函数,比如strcpyprintf等,都不能够被使用在这个假字符串上。    

    问题5const & 指针 

    类型声明中const用来修饰一个常量,有如下两种写法,那么,请问,下面分别用const限定不可变的内容是什么

    1)const在前面 

  const int nValue //nValueconst 

  const char *pContent; //*pContentconst, pContent可变   const (char *) pContent;//pContentconst,*pContent可变   char* const pContent; //pContentconst,*pContent可变   const char* const pContent; //pContent*pContent都是const      2)const在后面,与上面的声明对等   int const nValue // nValueconst 

  char const * pContent;// *pContentconst, pContent可变   (char *) const pContent;//pContentconst,*pContent可变   char* const pContent;// pContentconst,*pContent可变   char const* const pContent;// pContent*pContent都是const      答案与分析: 

    const和指针一起使用是C语言中一个很常见的困惑之处,在实际开发中,特别是在看别人代码的时候,常常会因为这样而不好判断作者的意图,下面讲一下我的判断原则: 

    沿着*号划一条线,如果const位于*的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;如果const位于*的右侧,const就是修饰指针本身,即指针本身是常量。你可以根据这个规则来看上面声明的实际意义,相信定会一目了然。 

    另外,需要注意:对于const (char *)  因为char *是一个整体,相当于一个类型( char),因此,这是限定指针是const    

  另=======  

  const用于函数时出现三个位置:   例如

  const returnVal function (const list_array)const;  

  第一个const意思是:返回值是常量  

  第二个const意思是:函数过程中不能修改list_array的值   第三个const意思是:函数过程不能隐式的修改function参数的值      ===    

  zzhttp://publishblog.blogchina.com/blog/tb.b?diaryID=3217823     

  const char*, char const*, char*const的区别问题几乎是C++面试中每次都会有的题目。   

  Bjarne在他的The C++ Programming Language里面给出过一个助记的方法:把一个声明从右向左读。    char * const cp; ( * 读成 pointer to ) cp is a const pointer to char    const char * p; p is a pointer to const char;    char const * p;  

  同上因为C++里面没有const*的运算符,所以const只能属于前面的类型。        

  :下面定义的一个指向字符串的常量指针:      char * const prt1 = stringprt1;  

    其中,ptr1是一个常量指针。因此,下面赋值是非法的。 ptr1 = stringprt2;      而下面的赋值是合法的: *ptr1 = "m";  

    因为指针ptr1所指向的变量是可以更新的,不可更新的是常量指针ptr1所指的方向(别的字符串)   

    下面定义了一个指向字符串常量的指针:      const * ptr2 = stringprt1;  

    其中,ptr2是一个指向字符串常量的指针。ptr2所指向的字符串不能更新的,而ptr2是可以更新的。因此,  

    *ptr2 = "x"; 是非法的,而: ptr2 = stringptr2; 是合法的。  

    所以,在使用const修饰指针时,应该注意const的位置。定义一个指向字符串的指针常量和定义一个指向字符串常量的指针时,const修饰符的位置不同,前者const放在*和指针名之间,后者const放在类型说明符前。

C++const用法总结

2人收藏此文章, 我要收藏发表于3年前(2010-08-28 21:39) , 已有168次阅读 ,共2个评论

看到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)。其中为用户自定义的数据类型。

对于非内部数据类型的参数而言,象void Func(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 &”修饰输入参数的用法总结一下。

 

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

 

b.对于内部数据类型的输入参数,不要将“值传递”的方式改为“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 GetA(void) 改写为const A & GetA(void)的确能提高效率。但此时千万千万要小心,一定要搞清楚函数究竟是想返回一个对象的“拷贝”还是仅返回“别名”就可以了,否则程序会出错。

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

例如:

class A

{

A & operate = (const A & other); // 赋值函数

} ;

A a, b, c; // a, b, c 的对象

 

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_data[100];

} ;

int Stack::GetCount(void) const

{

++ m_num; // 编译错误,企图修改数据成员m_num

Pop(); // 编译错误,企图调用非const 函数

return m_num;

}

const 成员函数的声明看起来怪怪的:const 关键字只能放在函数声明的尾部,大概是因为其它地方都已经被占用了。

关于Const函数的几点规则:

 

a. const对象只能访问const成员函数,而非const对象可以访问任意的成员函数,包括const成员函数.

b. const对象的成员是不可修改的,然而const对象通过指针维护的对象却是可以修改的.

c. const成员函数不可以修改对象的数据,不管对象是否具有const性质.它在编译时,以是否修改成员数据为依据,进行检查.

d. 然而加上mutable修饰符的数据成员,对于任何情况下通过任何手段都可修改,自然此时的const成员函数是可以修改它的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值