mutalbe的中文意思是“可变的,易变的”,跟constant(既C++中的const)是反义词。
在C++中,mutable也是为了突破const的限制而设置的。被mutable修饰的变量,将永远处于可变的状态,即使在一个const函数中。
我们知道,如果类的成员函数不会改变对象的状态,那么这个成员函数一般会声明成const的。但是,有些时候,我们需要在const的函数里面修改一些跟类状态无关的数据成员,那么这个数据成员就应该被mutalbe来修饰。
下面是一个小例子:
| class ClxTest { public: void Output() const; }; void ClxTest::Output() const { cout << "Output for test!" << endl; } void OutputTest(const ClxTest& lx) { lx.Output(); } |
类ClxTest的成员函数Output是用来输出的,不会修改类的状态,所以被声明为const的。
函数OutputTest也是用来输出的,里面调用了对象lx的Output输出方法,为了防止在函数中调用其他成员函数修改任何成员变量,所以参数也被const修饰。
如果现在,我们要增添一个功能:计算每个对象的输出次数。如果用来计数的变量是普通的变量的话,那么在const成员函数Output里面是不能修改该 变量的值的;而该变量跟对象的状态无关,所以应该为了修改该变量而去掉Output的const属性。这个时候,就该我们的mutable出场了——只要 用mutalbe来修饰这个变量,所有问题就迎刃而解了。
下面是修改过的代码:
| class ClxTest { public: ClxTest(); ~ClxTest(); void Output() const; int GetOutputTimes() const; private: mutable int m_iTimes; }; ClxTest::ClxTest() { m_iTimes = 0; } ClxTest::~ClxTest() {} void ClxTest::Output() const { cout << "Output for test!" << endl; m_iTimes++; } int ClxTest::GetOutputTimes() const { return m_iTimes; } void OutputTest(const ClxTest& lx) { cout << lx.GetOutputTimes() << endl; lx.Output(); cout << lx.GetOutputTimes() << endl; } |
计数器m_iTimes被mutable修饰,那么它就可以突破const的限制,在被const修饰的函数里面也能被修改。
-------------------------------简朴的分割线----------------------------------
我们知道在用const修饰的类成员函数,这意味着什么,从effective c++这本书上我们可以了解到,这里存在两个流行的概念:bitwise constness(or physical constness)和logical constness.
bitwise const阵营的人相信,成员函数只有在不更改对象任何成员变量(static变量除外)时才可以说是const.也就是说它不能更改对象内的任何一个bit.然而我们不难发现有些例子能够通过bitwise测试却存在潜在的改变成员变量的危险,比如说:
点击(此处)折叠或打开
- class String{
- public:
- String(char* pstring):pstring_(pstring)
- {
- }
- char& operator[](int index)const
- {
- ...
- return pstring_[index];
- }
- private:
- char* pstring_;
- };
客户可以写下如下代码:
const String str("any man of mine!");
char& c=str[0]; //call const-function
c='B'; //modified 'pstring_ ' from outer
这样写很显然不符合const的基本出发点(不能改变对象的属性),但是operator[]是通过bitwise测试的,编译器是能通过的,但不是我们想要的理想目标.
这种情况下就导出了logical constness,这一派主张一个const成员函数可以修改它所处理对象的某些位,但只有在客户端侦测不出来的时候才应如此.这种主张就导致了关键字mutable的诞生,它的作用是const函数实现体内可以修改由关键字mutable修饰的成员变量.比如我们修改一下前面一段代码:
点击(此处)折叠或打开
- class String{
- public:
- String(char* pstring):pstring_(pstring)
- {
- }
- char& operator[](int index)const
- {
- ...
- return pstring_[index];
- }
- //add new function to get the length of string
- int getLength()const
- {
- if(!isValidLength_)
- {
- stringLength_ = strlen(pstring_);
- isValidLength_ = true;
- }
- return isValidLength_;
- }
- private:
- char* pstring_;
- mutable bool isValidLength_;
- mutable int stringLength_;
- };
这里新增的函数getLength虽然有const修饰,但是实现体中我们修改了关键字mutable修饰的成员变量,编译器是容许我们这么做的。
mutable修饰的类成员变量的值可以在同一个类的const成员函数中被修改.