被const修飾的函數

被const修飾的函數

標籤(空格分隔):c/c++


部分參考:http://www.tuicool.com/articles/Nz6N3e

  • 用const修飾函數的參數

    如果輸入參數採用 指針傳遞 ,那麼加 const 修飾可以防止意外地改動該指針,起到保護作用。
    例如 StringCopy 函數:

    void StringCopy(char *destination, const char *source);

      如果輸入參數採用“值傳遞”,由於函數將自動產生臨時變量用於複製該參數,則輸入參數無需保護,所以不要加 const 修飾,即不是所有的入參都需要進行const保護。

    【一種特殊的情況】
      即對於非內部數據類型的參數而言,像 void func(A 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),以便提高效率?完全沒有必要,因爲內部數據類型的參數不存在構造、析構的過程,而複製也非常快,“值傳遞”和“引用傳遞”的效率幾乎相當。

    【總結一下】
    

    (1)對於非內部數據類型的輸入參數,應該將“值傳遞”的方式改爲“const 引用傳遞”,目的是提高效率。例如將 void func(A a) 改爲 void func(const A &a)。
    (2)對於內部數據類型的輸入參數,不要將“值傳遞”的方式改爲“const 引用傳遞”。否則既達不到提高效率的目的,又降低了函數的可理解性。例如 void func(int x) 不應該改爲void func(const int &x)。

  • 用const 修飾函數的返回值
      如果給以“指針傳遞”方式(返回值)的函數返回值加 const 修飾,那麼函數返回值(即指針)的內容不能被修改, 該返回值只能被賦給加 const 修飾的同類型指針。

      如下語句將出現編譯錯誤:
      char *str = getString();
      正確的用法是:
      const char *str = getString();

      如果函數返回值採用“值傳遞方式”,由於函數會把返回值複製到外部臨時的存儲單元中,加const 修飾沒有任何價值。例如,不要把函數 int getInt(void) 寫成 const int getInt(void)。同理不要把函數 A getA(void) 寫成 const A getA(void),其中 A 爲用戶自定義的數據類型。

      如果返回值不是內部數據類型,將函數 A getA(void) 改寫爲 const A & getA(void) 的確能提高效率。但此時千萬千萬要小心,一定要搞清楚函數究竟是想返回一個對象的“拷貝”還是僅返回“別名”就可以了,否則程序會出錯。

  • const 成員函數
    任何不會修改數據成員的函數都應該聲明爲 const 類型。
    在類中,const關鍵字位於函數名之後的位置(注意寫法),比如:

    class classname{
        ...
        int GetCount(void) const; // const 成員函數
        ...
    };
    • 總結

      關於 const 函數的幾點規則:

      • const 對象只能訪問 const 成員函數(類似於類的靜態成員函數),而非 const 對象可以訪問任意的成員函數,包括 const 成員函數。
      • const 對象的成員是不可修改的,然而 const 對象通過指針維護的對象(指針對象作爲成員)卻是可以修改的。
      • const 成員函數不可以修改對象的數據,不管對象是否具有 const 性質。它在編譯時,以是否修改成員數據爲依據,進行檢查。
      • 然而加上 mutable 修飾符的數據成員,對於任何情況下通過任何手段都可修改,自然此時的 const 成員函數是可以修改它的。

      【解釋:爲什麼const對象只能訪問const成員函數
        當我們的對象是const對象時,比如 const CTest ttt; 這時候表示什麼意思呢?ttt的內容是不可以改變的,當我們把&ttt作爲一個參數傳到形參this時,矛盾出現了:(1)ttt的成員不可以被改變。(2)this指針的成員變量是可以改變的(只是this指向的對象地址不能改變)。如果我能正確的將ttt的地址傳給this,那麼ttt這個常量的值就可以在this中被改變了!,所以,編譯器是不允許這種情況出現的,也就是說如果我們用const對象訪問了非const成員函數就提示錯誤了。故,const對象不能訪問非const成員函數。
        當我們的成員函數是const成員函數時,例: CTest::ttt() const; ,在編譯器解釋時會將該函數解釋爲 CTest::ttt(const CTest const this) ,this指針及其所指向的內容都不可以被修改,前面提到的矛盾也就不存在了,所以const對象可以訪問const成員變量。

      【const成員函數的訪問權限】
      a. const成員函數不被允許修改它所在對象的任何一個數據成員。
      b. const成員函數能夠訪問對象的const成員,而其他成員函數不可以。


  • 補充

    • 使用const的優點之節省空間、提高效率
      【節省空間】const定義常量從彙編的角度來看,只是給出了對應的內存地址,而不是象#define一樣給出的是立即數,所以,const定義的常量在程序運行過程中只有一份拷貝,而#define定義的常量在內存中有若干個拷貝。
      【提高效率】編譯器通常不爲普通const常量分配存儲空間,而是將它們保存在符號表中,這使得它成爲一個編譯期間的常量,沒有了存儲與讀內存的操作,使得它的效率也很高。

    • const修飾成員變量
      const修飾類的成員,表示成員常量,不能被修改,同時它只能在初始化列表中賦值

    • 將const類型轉化爲非const類型的方法
      採用const_cast 進行轉換。
      用法: const_cast <type_id> (expression)

    • 其他補充
        如果在非const成員函數中,this指針只是一個類類型的;如果在const成員函數中,this指針是一個const類類型的(底層的const,this本身是默認頂層的const);如果在volatile成員函數中,this指針就是一個volatile類類型的。
        new返回的指針必須是const類型的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章