2014年7月18日 星期五

const 與 mutable

假設您設計了一個Ball類別:
  • Ball.h
#include <string>
using namespace std;

class Ball { 
public: 
    Ball(); 
    Ball(double, const char*); 
    Ball(double, string&); 
 
    double radius() {
        return _radius;
    }
 
    string& name() {
        return _name; 
    }
 
    void radius(double radius) {
        _radius = radius;
    } 
 
    void name(const char *name) {
        _name = name;
    }
 
    void name(string& name) {
        _name = name;
    }
 
    double volumn() {
        return (4 / 3 * 3.14159 * _radius * _radius * _radius); 
    }
 
private:
    double _radius; // 半徑 
    string _name; // 名稱 
};

假設您現在設計了一個somefun()函式:
void somefun(const Ball &ball) {
     ball.radius();
}

在函式的參數列上,您使用const宣告了ball參數,在編譯時會出現以下的訊息:

passing `const Ball' as `this' argument of `double Ball::radius()' discards qualifiers 

由於參數列上ball使用了const來宣告,這表示您不可以更動ball實例的狀態,也就是不得(在呼叫函式時)更動ball的資料成員,為了讓編譯器 得知這項訊息,您要在所呼叫的函式上加上const,例如:

void radius() const {
    return _radius;
}

編譯器會檢查每個被標示為const的成員函式,看看當中的陳述有無更動物件的資料成員。

另一方面還有一個問題,假設您在somefun()函式中如下呼叫:

void somefun(const Ball &ball) {
     ball.name();
}

則編譯時會出現以下的錯誤訊息:

`const Ball' as `this' argument of `std::string& Ball::name()' discards qualifiers 

即使您在name()函式後加上const,編譯時照樣無法通過,原因在於name()是以傳參考的方式傳回,而不是以傳值的方式傳回,由於以傳參考的方 式傳回,接受傳回值的物件可以直接更改傳回值,因而影響被呼叫物件的狀態,為了保證傳回值不被修改,您要在傳回值宣告上加上const,也就是:

const string& name() const {
    return _name; 
}

有時候您會希望大部份成員在const成員函式中不被更改,但少數幾個資料成員允許它們在const成員函式中被更動,因為這 些資料成員被 變動並不被視為改變了物件的狀態,這時候您可以在該資料成員宣告時加上mutable,表示對該成員的變動並不代表對物件狀態的改變,例如: 

class SomeClass { 
public: 
    ....
    double increment() const { 
        return _index++; 
     } 

private:
    .... 
    mutable double _index; 
};


沒有留言:

張貼留言