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;
};