const基础用法

来源:互联网 发布:淘宝有没有货到付款的 编辑:程序博客网 时间:2024/04/28 09:40

一 const基础

如果const关键字不涉及到指针,我们很好理解,下面是涉及到指针的情况:

int b = 500;
const int* a = &b; [1]
int const *a = &b; [2]
int* const a = &b; [3]
const int* const a = &b; [4]

如果你能区分出上述四种情况,那么,恭喜你,你已经迈出了可喜的一步。不知道,也没关系,我们可以参考《Effective c++》Item21上的做法,

如果const位于星号的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;

如果const位于星号的右侧,const就是修饰指针本身,即指针本身是常量。

因此,[1]和[2]的情况相同,都是指针所指向的内容为常量(const放在变量声明符的位置无关),这种情况下不允许对内容进行更改操作,如不能*a = 3 ;

[3]为指针本身是常量,而指针所指向的内容不是常量,这种情况下不能对指针本身进行更改操作,如a++是错误的;

[4]为指针本身和指向的内容均为常量。

二 作为参数

void display(const double& r);或者void display(const double* r);

说明:

1 在引用或者指针参数的时候使用const限制是有意义的,而对于值传递的参数使用const则没有意义

2 保证引用的变量的值不被改变

3 const在double前或者后面意思相同,只是不同的人的写法不同

三 const对象

声明为const的对象只能访问类中声明为const的成员函数,不能调用其它成员函数.

四 const成员函数

类型说明符   函数名(参数表)const;             void print(int i) const;

说明:

1 const是函数类型的一个组成部分,因此在实现部分也要带const关键字.

2 常成员函数不能更新对象的数据成员,也不能调用该类中没有用const修饰的成员函数.


五 使用const的一些建议

1 要大胆的使用const,这将给你带来无尽的益处,但前提是你必须搞清楚原委;
2 要避免最一般的赋值操作错误,如将const变量赋值,具体可见思考题;
3 在参数中使用const应该使用引用或指针,而不是一般的对象实例,原因同上;
4 const在成员函数中的三种用法(参数、返回值、函数)要很好的使用;
5 不要轻易的将函数的返回值类型定为const;
6除了重载操作符外一般不要将返回值类型定为对某个对象的const引用;

 

================================================

 

1.使用const的好处 
   1.1在<<C++编程规范>>中的说法是“尽量使用const来代替#define”. 如果你使用下面的语句定义一个宏(宏:文字替换而已)
         #define MAX_LENGTH 100
   MAX_LENGTH这个名字就只能被编译器的预处理程序所看到,程序中所有出现MAX_LENGTH的地方都被预处理程序替换为100,此后编译器看到的只是100这个常数。当宏较大较复杂且有错时,编译器报出的错误可能是难以理解的。这时如果我们用
         const int MAX_LENGTH = 100;   
   编译器就可以看到MAX_LENGTH这个符号,并且可以对MAX_LENGTH进行类型检查,在代码发生错误时也能正确地报出错误位置。

   1.2在团队开发中有用,比如你写一个函数计算字符串的长度,原型写成int MyStrLen(const char * str),则表示这个函数并不会改变str所指向的内容(即*str).这样使用起来更加安全,该const限制能保证团队的开发人员按正确的方式使用已有代码。

2.使用const来标识常量
这个是笔试喜欢考的东东,考改错的可能性比较大,或者问答题(偶上次TrendMicro考的是改错题,偶做得还不错)

   //整型常量,以后不能再对它赋值,因此必需赋一个初值
   int const number = 1;

   //同上,可见const 放在int 前面或后面的意义是一样的
   const int number = 1;

   //指向常量的变量指针,*p不可变,p可变(可指向别处)
   int const *p;
 
   //同上,可见const 放在int 前面或后面的意义是一样的
   const int *p;  

   //指向变量的常量指针,p不可变,但p指向的内容number1可变,p以后不能改变,所以必须赋初值     
   int* const p = &number1;     
   
   //指向常量的常量指针,p不可变,number也不可变,p以后不能改变,所以必须赋初值
   const int * const p = &number;

   //引用,C++引用都是常量引用,引用的指向不可变,一个引用指向一个变量后就不能再改变它使它指向另一个变量(因此必
   //须赋初值),当然引用所指向的内容可以改变(人家指向的是变量嘛),引用一般是出现在函数的参数中
   int & number2 = number;

这个其实很容易记的,主要是看const修饰的是谁

3.修饰类的常量成员
   如果一个常量只会在一个类里使用,那么我们就不应该把它定义为全局常量,我们应该把我定义在类的内部
   class Example
   {
    public:
       const int MAX_LENGTH = 100;
   };

   上述代码虽然能通过编译,但存在一下悖论,MAX_LENGTH既然是一个常量,那么它一定不会改变,按照上面的代码,类的每一个对象(也称实例)中都会有一份MAX_LENGTH的COPY,这不是在白白浪费内存?所以通常类中的常量应当定义为一个静态变量,标准的代码如下
   class Example
   {
    public:
       static const int MAX_LENGTH;//static 的常量不能在类中定义,要移到外面去
   };
   const int Example::MAX_LENGTH = 100;//static 的常量不能在类中定义

4.修饰函数的参数
   大家都知道C++中函数的参数是按值传递的,当我们要传入一个大型对象的时候,使用按值传递就很不实惠,因为按值传递会生成该对象的一个COPY.浪费呀!!因此在传递对象的时候最好使用指针或引用.
   但是在一般情况下,我们并不希望函数改变我们所传入的参数,而使用指针或引用做参数就存在被修改的可能性.
   因此对于不应当被修改的东东我们应当使用const来修饰之

   比如写一个字符串COPY的函数
   bool CopyString(MyString& szDest,const MyString& szSrc);//假设MyString是我自己定义的一个字符串类
   上面的函数表明,源字符串szSrc不会(也不应当)被CopyString函数修改,而目标字符串szDest当然要改变了.

5.修饰类的成员函数
   先写一个不用const修饰成员函数的类
   class MyString//我的字符串类(仅仅用于教学,没有什么实际的意义)
   {
   //......
   private:
      int len;
   public:
     int GetLength();//获得串的长度 
     void SetLength(int len);//设置长度
      //......
   };
   ///GetLength的实现
   int MyString::GetLength()
   {
      return this->len;
   }
   ///SetLength的实现
   void MyString::SetLength(int len)
   {
      this->len = len;
   }

   类的成员函数(内联除外)是另外安排空间的,并不放在类的里面,类的各个对象调用的都是外部的同一个函数.如:
   MyString s1;
   MyString s2;
   s1.SetLength(1);
   s2.SetLength(2);

   s1与s2调用的是同一份函数体,那SetLength(...)如何区分来自于不同的对象的调用呢?参考<<深度探索C++对象模型>>可知道
   其实GetLength函数的原型并不是GetLength( ),而是GetLength(MyString * const this),当s1调用GetLength时其实是调用GetLength(s1),这里用const 来修饰this说明this是一个不可变的指针,你不能在GetLength函数里把它指向别处,当然你可以改变this所指向的内容.
   使用const修饰类的成员函数(就是在括号后加上一个const,形如:int GetLength()const;),编译器会为我们生成以下函数
   GetLength(MyString const  * const this)
   由该原型可以看出,const修饰成员函数的作用在于:表明该成员函数不会修改*this内容,比如GetLength的职责只是返回字符串的长度,而不是修改对象中的任何数据.

   下面说说作用(也就是笔试考点 PS:前几天趋势公司考过,怕大家以后笔试遇到,于是就帖出来了
   bool CopyString(MyString & szDest,const MyString & szStr)
   {
       //......
       szDest.SetLength(szStr.GetLength());//假设我们就只做这件无聊的事
       //......
   }

   如果GetLength不是const型,则不能编译通过,解释如下
   CopyString的第二个参数 const MyString & szStr表明szStr是一个const引用,当szStr.GetLength()时传递给GetLength的第一个参数是szStr 的类型是MyString const *const szStr,
而未经const修饰的GetLength接受的第一个参数是MyString * const this,两者不匹配编译出错
   
   如果用const修饰GetLength则GetLength的第一个参数是MyString const  * const this 与szStr匹配,编译通过

 

原创粉丝点击