C++ const學習


 

概念

  const就是為了直接表達“不變化的值”這一概念。也就是說該值只可讀,不可直接寫。
  由於不可以修改,所以const常量在聲明的時候必須初始化

    const int a;    //error
    extern    const int ext_a;

 

作用

  •  可以定義const常量,具有不可變性 
        const int a = 4 ;
        //a = 5;      //error
  • 便於類型檢查,使編譯器對處理內容有更多了解
    如 a = 5 在編譯的時候可以將對const常量進行修改的部分檢查出來
  • 保護被修飾的內容
    我們一直在建議不要修改函數的參數值,便於調試、維護,以及減少不必要的錯誤,但函數的調用者與函數的編寫者,所以無法人為的保證傳入的參數無法被修改,此時就運用const,運用編譯器對代碼進行檢查。主要還是和引用參數聯合使用,如果只是修改參數對調用者沒影響還好說,否則...(后續詳談)
    void fun1(const int a)
    {
        //a=5;
    }
    
    void fun2(const ClassA& a)
    {
        //a.xx=xx 
    }
  • 提高代碼的可讀性、維護性
    運用const常量替換代碼中出現的比較多的各種文字量,個人認為代碼中出現數字0、1,閱讀時還能理解,但是要是突然出來一個2、5、8,這是什么意思呢?可能自己寫的代碼過一陣子自己也不清楚了,此時我們就可以運用const常量或enum起一個合適的名字替代這些不易理解的數字。如果是字符串的話就只能運用const了,呃,或者是宏#define(個人不太喜歡宏,原因1.宏易出錯,不易理解;2.編譯器無法檢查類型;3.C++不建議使用宏)
  • 函數重載
    兩個重載函數必須在下列一個或兩個方面有所區別:
    1、參數數量不同
    2、參數類型不同
      如下 funA以上兩個方面都不滿足,但是卻可以重載,const函數對應const對象使用(后續詳談)
  • class ClassA
    {
    public:
        void funA()
        {
       //... }
    void funA() const { //... } }; 

 const與指針

  The C++ Programming Language里面給出過一個助記的方法:  把一個聲明從右向左讀。

    char * const p1;          //p1 is a const pointer to char
    const char *p2;            //p2 is a pointer to const char
    const char * const p3;    //p3 is a const pointer to const char

  Effective C++同樣給出了一種方式,如果關鍵字const在星號的左邊,表示被指物是常量;如果出現在星號右邊,表示指針自身是常量;如果出現在兩邊,表示被指物和指針二者都是常量。其實指針只要分清指針本身與所指向的內容即可。個人覺得不用糾結與有些書上的叫法什么“指針常量”,“常量指針”,這都是在翻譯的過程中帶來的歧義。

  如p1是一個const pointer,所以在聲明的時候必須初始化,否則編譯不通過,而*p1則是char類型。
  p2是一個pointer但不是const,*P2才是const類型,所以p2可以不用初始化。

  那么p1聲明指向的為char 是否可以指向const char 呢?p2聲明指向的為const char 是否可以指向char類型呢?

    const char ca = 'a' ;
    char b= 'b';

    char *p;
    //p=&ca;                //error
    p=&b;
    char * const p1=&b;
    //char * const p1=&ca;        //error    
    const char *p2;
    p2=&ca;
    p2=&b;                        //ok
    const char * const p3=&b;    //ok

 

  因為對承諾不修改的內容要被修改,肯定是有問題的;但對可修改的內容不做修改沒有任何問題。如上面ca不可修改,*p可以修改,所以p=&ca錯誤;而b可以修改,*p1不可以修改,p=&b對b不會造成不良影響,所以可以通過。

  那么是不是非const類型可以直接賦值與const類型呢?而const類型不能直接賦值與非const類型呢?

    ClassA ca;
    const ClassA cst_b;

    ClassA cc=cst_b;    //copy構造函數可以理解
    ClassA c2;
    c2=cst_b;            //??
    const ClassA cst_d=ca;     

    int a=1;
    const int b=a;
    int c=b;            //??

  以上代碼完全可以編譯通過,那該怎么解釋呢?個人理解為如果賦值后的對象不對原對象代碼不良影響,都是可以通過的。如int c=b;c的修改不會修改b;c2=cst_b,調用ClassA的賦值操作ClassA& operator=(const ClassA&),也同樣不會對原cst_b修改。

 const與引用

   引用與指針有所不同,因為引用本身可以看作是一個常量指針,引用在聲明是必須初始化,且不可以在引用值其他對象。所以引用只存在一種形式。const type& 而type& 與type& const 等價。const 引用主要運用在函數的參數傳遞方面。Effective C++ 第20條 Perfer pass-by-reference-to-const to pass-by-value.

    int a;
    int & ref1=a;
    const int & ref2 =a;
    int & const ref3=a;        //沒必要

const與函數

   函數與const 的關系可以從三部分來看,返回值、參數、函數自身

  • const修飾返回值
    class ClassA
    {
    public:
        int a;
    
        ClassA():a(1)
        {
        }
        const int funA()   //沒意義,因為返回值本身就無法修改 與int funA()一樣,而且也不存在funA()=4這種寫法
        {
            return a;    
        }
        int * const funB() //與funA一樣,const的限定的是返回值的指針,也無法修改 。與int *  funB() 一樣
        {
            return &a;
        }
        const int * funC() //const修飾的是返回指針所指內容,所以該函數的接收這也必須為const int*類型
        {                        
            return &a;
        }
        const int &funD()   //返回引用,該引用不可以修改
        {
            return a;
        }
        void test()
        {
            int re=funA();
            int *p=    funB();
    
            //int *p1=funC();        //error
            const int *p2=funC();
    
            //int& c=funD();         //error
            const int& a2=funD();
             
        }
    };

     funA、funB其實實際意義都不大,因為不論返回值是不是const類型,函數調用者都不可能修改返回值的實際值。而函數調用者該不該用const與函數本身沒關系。
    cosnt自定義類型返回值,往往可以降低因函數調用者錯誤而造成的以外,而又不至於放棄安全性和高效性

    ClassA funCA()
    {
        ClassA a;
        return a;
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        ClassA ca;
        funCA()=ca;
    }
      funCA()=ca;這句話具體有什么實際意義呢?沒意義,但是就是可以編譯通過,此時就可以將funCA返回值限定為const ClassA,這樣的寫法首先編譯器都不通過。
  • const修飾函數參數
      Effective C++ 至於const參數,沒什么特別新穎的觀念,它們不過就像local const對象一樣,你應該在必要使用它們的時候使用它們。除非你有需要修改參數或者loacl對象,否則請將他們聲明為const。
        int funA(const int a);
        int funB(int * const p);
        int funC(const int *p);
        int funD(const int& ra);
  • const修飾成員函數自身
    將const實施於成員函數的目的,是為了確認該成員函數可以作用與const對象身上。這類函數有兩個理由顯得重要
    1.是class接口比較容易被理解。2.const對象使用
    class ClassA
    {
    
    public:
        int a;
    
        ClassA():a(1)
        {
        }
    
        void fun()
        {
            a=5;
            cout<<"this is not a const function"<<endl;
        }
        void fun() const
        {
            //    a=5;    //error
            cout<<"this is a const function"<<endl;
        }
    };
    int _tmain(int argc, _TCHAR* argv[])
    {
    
        ClassA ca;
        ca.fun();    //this is not a const function
    
        const ClassA cb;
        cb.fun();    //this is a const function
    }

    const對象只能調用const函數,且const函數不能對成員函數做修改。若將void fun()函數刪掉,則編譯不通過錯誤提示:ClassA::fun”: 不能將“this”指針從“const ClassA”轉換為“ClassA &;若將void fun() const 函數刪掉,則ca.fun()調用const fun。

   今天快下班了,先寫這些吧,明天補充總結!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM