深入浅出const
§通常,如果一个对象通过引用方式传到函数f中,而函数f又不会通过修改对象的数据成员的值改变该对象的状态,那么,我们最好将f的参数标记为const,这样可以预防对参数的误写,同时有些编译器还可对这种情况进行一些优化。
如下:将函数setName的string类型参数n标记为const,表明setName不会改变n,只是将n赋值给数据成员name。
1 class C 2 { 3 public: 4 void setName(const string &n) 5 { 6 name = n; 7 } 8 //...other public members 9 private: 10 string name; 11 };
§如果一个成员函数不需要直接或间接(通过调用其他的成员函数考改变其队形状态)地改变该函数所属对象的任何数据成员,那么最好将这个成员函数标记为const。
如下,由于get成员函数不需要改变类C 的任何数据成员,因此将get成员函数标记为const。
1 class C { 2 public: 3 void set(int n) { num = n;} 4 int get() const {return num;} 5 private: 6 int num; 7 };
说明:
<1>由于get成员函数不更改任何数据成员,因此这种类型的函数被称为只读函数。
<2>将成员函数标记为const可以预防对该函数所属对象的数据成员的误写,同时有些编译器还可以对这种情况进行一些优化。
<3>一个const成员函数仅能调用其他const成员函数;因为const成员函数不允许直接或间接地改变对象的状态,而调用非const成员函数可能会间接地改变对象的状态。
例如:
1 class C { 2 public: 3 void m1(int x) const { 4 m2(x); //***error 5 } 6 7 void m2(int x){dm = x;} 8 private: 9 int dm; 10 };
§const关键字三种不同的用法实例
——在成员函数set中,因为set不改变string类型参数n,n被标记为const。
——成员函数get返回数据成员name的一个const型引用,此处的const表明谁也不能通过这个引用来修改数据成员name的值。
——成员函数get本身被标记为const,因为get不会改变类C唯一的数据成员name的值。
例如:
1 class C{ 2 public: 3 void set(const string &n) {name = n;} 4 const string &get() const {return name;} 5 private: 6 string name; 7 };
因此有:
(1)某函数如果采用const返回,则其返回值只能付给一个const类型的局部变量。
(2)如果该const返回值是一个类的指针或者引用的话,则不能用该指针或引用调用该类的non-const成员函数,因为这些函数可能会改变该类的数据成员的值。
综合以上我们来看这样一个例子:
1 #include<iostream> 2 using namespace std; 3 class sz 4 { 5 public: 6 int &f1() //可修改mazT,可修改返回值 7 {mszT = 5; return mszT;} 8 9 int f2() cosst //不能修改mszT,可修改返回值 10 {return mszT;} 11 12 const int &f3() //可修改mszT, 不可修改返回值 13 {mszT = 6; return mszT;} 14 15 const int& f4 const //不可修改mszT, 不可修改返回值 16 {return mszT;} 17 18 void print() 19 {cout<<mszT<<endl;} 20 21 private: 22 int mszT; 23 }; 24 25 int main() 26 { 27 sz f; 28 int &s1 = f.f1(); //OK 29 cout<<s1<<endl; //输出:5 30 s1 = 20; //可修改返回值 31 f.print(); //输出:20 32 33 int &s3 = f.f3(); //Error, 返回const值,但s3不是const 34 const int & s3 = f.f3() //OK 35 cout<<s3<<endl; //输出:5 36 s3 = 20; //Error,修改返回值 37 38 return 0; 39 }