1. 程式人生 > >C++的const類成員函式

C++的const類成員函式

我們知道,在C++中,若一個變數宣告為const型別,則試圖修改該變數的值的操作都被視編譯錯誤。例如,

  1. constchar blank = ‘’;  
  2. blank = ‘\n’;  // 錯誤

        面向物件程式設計中,為了體現封裝性,通常不允許直接修改類物件的資料成員。若要修改類物件,應呼叫公有成員函式來完成。為了保證const物件的常量性,編譯器須區分不安全與安全的成員函式(即區分試圖修改類物件與不修改類物件的函式)。例如,

  1. const Screen blankScreen;  
  2. blankScreen.display();   // 物件的讀操作
  3. blankScreen.set(‘*’);    // 錯誤:const類物件不允許修改

        在C++中,只有被宣告為const的成員函式才能被一個const類物件呼叫。

        要宣告一個const型別的類成員函式,只需要在成員函式引數列表後加上關鍵字const,例如,

  1. class Screen {  
  2. public:  
  3.    char get() const;  
  4. };  

        在類體之外定義const成員函式時,還必須加上const關鍵字,例如

  1. char Screen::get() const {  
  2.    return _screen[_cursor];  
  3. }  

        若將成員成員函式宣告為const,則該函式不允許修改類的資料成員。例如,

  1. class Screen {  
  2. public:  
  3. int ok() const {return _cursor; }  
  4. int error(intival) const { _cursor = ival; }  
  5. };  

        在上面成員函式的定義中,ok()的定義是合法的,error()的定義則非法。

        值得注意的是,把一個成員函式宣告為const可以保證這個成員函式不修改資料成員,但是,如果據成員是指標,則const成員函式並不能保證不修改指標指向的物件,編譯器不會把這種修改檢測為錯誤。例如,

  1. class Name {  
  2. public
    :  
  3. void setName(const string &s) const;  
  4. private:  
  5.     char *m_sName;  
  6. };  
  7. void setName(const string &s) const {  
  8.     m_sName = s.c_str();      // 錯誤!不能修改m_sName;
  9. for (int i = 0; i < s.size(); ++i)   
  10.     m_sName[i] = s[i];    // 不好的風格,但不是錯誤的
  11. }  

        雖然m_Name不能被修改,但m_sName是char *型別,const成員函式可以修改其所指向的字元。

        const成員函式可以被具有相同引數列表的非const成員函式過載,例如,

  1. class Screen {  
  2. public:  
  3. char get(int x,int y);  
  4. char get(int x,int y) const;  
  5. };  

        在這種情況下,類物件的常量性決定呼叫哪個函式。

  1. const Screen cs;  
  2. Screen cc2;  
  3. char ch = cs.get(0, 0);  // 呼叫const成員函式
  4. ch = cs2.get(0, 0);     // 呼叫非const成員函式

小結:

1)const成員函式可以訪問非const物件的非const資料成員、const資料成員,也可以訪問const物件內的所有資料成員;

2)非const成員函式可以訪問非const物件的非const資料成員、const資料成員,但不可以訪問const物件的任意資料成員;

3)作為一種良好的程式設計風格,在宣告一個成員函式時,若該成員函式並不對資料成員進行修改操作,應儘可能將該成員函式宣告為const 成員函式。

參考資料:

《C++ Primer第三版》

《Effective C++第三版》