可变数据成员:
有时我们希望能修改某个类的数据成员,即使是在一个 const 成员函数内。可以通过在变量的声明中加入 mutable 关键字来声明一个可变数据成员。mutable 是为突破 const 的限制而设置的。被 mutable 修饰的变量将永远处于可变状态中,即使是在一个 const 成员函数中:
1 #include <iostream> 2 using namespace std; 3 4 class gel{ 5 private: 6 mutable size_t access_ctr; 7 8 public: 9 gel() = default; 10 gel(const int &x):access_ctr(x){} 11 // ~gel(); 12 13 void out_put() const{ 14 cout << access_ctr << endl; 15 } 16 17 void some_member(void) const{ 18 ++access_ctr; 19 } 20 }; 21 23 int main(void){ 24 const gel x(1); 25 x.out_put();//输出1 26 x.some_member(); 27 x.out_put();//输出2 28 x.some_member(); 29 x.out_put();//输出3 30 return 0; 31 }
关于 mutable 关键字存在的必要性:https://www.zhihu.com/question/64969053/answer/226383958
基于 const 的重载:
1 #include <iostream> 2 using namespace std; 3 4 class gel{ 5 private: 6 int x; 7 8 public: 9 gel() = default; 10 gel(int val): x(val){} 11 12 const gel &display(std::ostream &os) const{ 13 std::cout << x; 14 return *this; 15 } 16 17 gel &count(void){ 18 x++; 19 return *this; 20 } 21 }; 22 23 int main(void){ 24 gel x(0); 25 x.display(cout); 26 x.count(); 27 // x.display(cout).count();//错误:display 返回的是一个 const 对象,而 count 不是常量函数 28 return 0; 29 }
一般来说像 x.display(cout); 与 x.count(); 应该是要可以写成 x.display(cout).count();的形式的。但这个代码中 display 返回的是一个 const 对象,所以后者显然是错误的。这是我们代码写的不合理,应该尽量避免写出这样的代码。我们可以通过重载解决这个问题:
1 #include <iostream> 2 using namespace std; 3 4 class gel{ 5 private: 6 int x; 7 8 public: 9 gel() = default; 10 gel(int val): x(val){} 11 12 gel &display(std::ostream &os){ 13 do_display(os); 14 // os << x;//在代码比较短的时候这样写也一样,不过要是代码量大的话显然要多写不少代码 15 return *this; 16 } 17 18 const gel &display(std::ostream &os) const{ 19 do_display(os); 20 // os << x; 21 return *this; 22 } 23 24 gel &count(void){ 25 x++; 26 return *this; 27 } 28 29 private: 30 void do_display(std::ostream &os) const{ 31 os << x; 32 } 33 }; 34 35 int main(void){ 36 gel x(0); 37 x.display(cout).count(); 38 return 0; 39 }
这里我们通过调用 display 的对象是否为常量来决定调用哪个 display 函数。需要注意的是这里是通过底层 const 来区分重载函数的(形参会忽略顶层 const),若调用 display 的对象是 const,那么隐式传递的 this 指针具有底层 const,反之则没有。
调用 display 的是非常量的话,display 返回的也是一个非常量对象,此时 x.display(cout).count();顺利执行;
调用 display 的是常量的话, display 返回的也是一个常量对象,此时 x.display(cout).count();报错。
显然,这个代码中的 x.display(cout).count();与 x.display(cout);x.count();是完全等价的。