const 与 mutable


如果在创建string实例时指定const,那表示不能变动该实例的状态,如果试图改变该实例状态,或者调用了会变动实例状态的方法,编译时会发生错误:

const string text = "Justin";
text.append(" Lin") // error: no matching function

const修饰表示不能变动实例状态,这并不是自动发生的事情,如果调用的方法没有被const修饰,就不能通过编译,例如,若如下使用〈定义类〉中的Account,虽然to_string并没有变动实例状态,也不能通过编译:

#include <iostream> 
#include "account.h"
using namespace std;

int main() {
    const Account acct = {"123-456-789", "Justin Lin", 1000};
    cout << acct.to_string() << endl; //  error: passing 'const Account' as 'this' argument discards qualifiers
}

如果要通过编译的话,to_string必须加上const限定:

account.h

#include <string>
using namespace std; 

class Account { 
private:
    string id;  
    string name; 
    double balance;

public: 
    Account(string id, string name, double balance);
    void deposit(double amount);
    void withdraw(double amount);
    string to_string() const;
};

account.cpp

...略

string Account::to_string() const {
    return string("Account(") + 
           this->id + ", " +
           this->name + ", " +
           std::to_string(this->balance) + ")";
}

...略

当方法被加上const限定后,方法就不能有改变值域的动作,有了这个保证,方才的to_string调用才能通过编译。

另一个类似的问题是:

#include <iostream> 
#include "account.h"
#include <string>
using namespace std;

class Foo {
public:
    Foo& doSome() {
        return *this;
    }
    Foo& doOther() {
        return *this;
    }
};

int main() {
    const Foo foo;
    foo.doSome().doOther();
}

这个程序在Foo foo前,若没有加上const的话,是可以通过编译的,你可能会想,那就在doSomedoOther函数本体前,也加上const就可以了吧!可惜…加上了还是不能通过编译!

const的要求很严格,不仅要求方法不能变动实例状态,如果以参考返回型值域,或者是如上以参考返回实例本身,也会要求返回值的状态不得改变,必须得如下才能通过编译:

#include <iostream> 
#include "account.h"
#include <string>
using namespace std;

class Foo {
public:
    const Foo& doSome() const {
        return *this;
    }
    const Foo& doOther() const {
        return *this;
    }
};

int main() {
    Foo foo;
    foo.doSome().doOther();
}

你可能会想在被限定为const的方法中,可以改变某些值域,因为这些值域的改变,从使用者来看,并不代表实例状态的改变。

这是什么意思呢?例如,若有个hashCode方法,可以计算出对象的散列值,实际上可以在首次调用该方法计算出散列值之后,使用值域将散列存储下来,对象的hashCode结果从使用者来看并没有变,若是有这类需求,值域在定义时,可以加上mutable

class Foo {
    mutable int hash = 0;

public:
    int hashCode() const {
        if(hash == 0) {
            // 计算散列值 v
            this->hash = v;
        }

        return this->hash;
    }
};




展开阅读全文