class Test(){ public: Test(){} const int foo(int a); const int foo(int a) const; };
一、概念
当const在函数名前面的时候修饰的是函数返回值。
当const在函数名后面表示是常成员函数,该函数不能修改对象内的任何成员,只能发生读操作,不能发生写操作。
二、原理:
我们都知道在调用成员函数的时候编译器会将对象自身的地址作为隐藏参数传递给函数,在const成员函数中,既不能改变this所指向的对象,也不能改变this所保存的地址,this的类型是一个指向const类型对象的const指针。
c++中关于const的用法有很多,const既可以修饰变量,也可以函数,不同的环境下,是有不同的含义。今天来讲讲const加在函数前和函数后面的区别。比如:
1 #include<IOStream> 2 3 using namespace std; 4 5 // Ahthor: 过往记忆 6 // E-mail: wyphao.2007@163.com 7 // Blog: http://www.iteblog.com 8 // 转载请注明出处 9 10 class TestClass { 11 public: 12 size_t length() const; 13 const char* getPContent(); 14 void setLengthValid(bool isLengthValid); 15 private: 16 char *pContent; 17 size_t contentLength; //A 18 bool lengthIsValid; //B 19 size_t precontentLength; 20 }; 21 22 size_t TestClass::length() const{ //函数名后加const 23 if(!lengthIsValid){ 24 contentLength= strlen(pContent); //C 25 lengthIsValid = true; //D 26 } 27 28 return contentLength; 29 } 30 31 const char* TestClass::getPContent(){//函数名前加const 32 return pContent; 33 } 34 35 void TestClass::setLengthValid(bool isLengthValid){ 36 lengthIsValid = isLengthValid; 37 } 38 39 int main(void){ 40 TestClass *tc =new TestClass; 41 tc->setLengthValid(false); 42 tc->length(); 43 char * content = tc->getPContent(); //E 44 return 0; 45 }
其中类TestClass中的length函数和getPContent函数分别在函数名后和前加了const修饰符,如果试图编译上面的代码,将会得到下面的错误:
1 --------------------配置: mingw5 - CUI Debug, 编译器类型: MinGW-------------------- 2 检查文件依赖性... 3 正在编译 C:UserswypDesktop未命名1.cpp... 4 [Error] C:UserswypDesktop未命名1.cpp:24: error: assignment of data-member `TestClass::contentLength' in read-only structure 5 [Error] C:UserswypDesktop未命名1.cpp:25: error: assignment of data-member `TestClass::lengthIsValid' in read-only structure 6 [Error] C:UserswypDesktop未命名1.cpp:43: error: invalid conversion from `const char*' to `char*' 7 [Warning] C:UserswypDesktop未命名1.cpp:45:2: warning: no newline at end of file 8 9 构建中止 未命名1: 3 个错误, 1 个警告
里面有三个错误,也就是代码C、D、E处的三个地方。为什么C和D处的代码会出错,原因如下:
length函数名的后面加了const修饰符,这样说明函数的成员对象是不允许修改的。我们都知道,在类的成员函数里面,默认是在成员函数的第一个位置是this指针,如果在成员函数(只能是成员函数,要是类的静态函数或者是非成员函数就不可以在函数名后面加上const)后面const,则说明this指针的值是不可以修改的,只能读取。而上面的length函数可能会修改里面的contentLength和lengthIsValid的值,这样编译器肯定是不允许的,所以这样是会出现错误的。
解决方法是:在类的A、B处的成员前面加上mutable修饰符:
1 mutable size_t contentLength; //A 2 mutable bool lengthIsValid; //B
从字面的意思知道,mutalbe是“可变的,易变的”,跟constant(既C++中的const)是反义词。在C++中,mutable也是为了突破const的限制而设置的。被mutable修饰的变量,将永远处于可变的状态,即使在一个const函数中。这样在C、D处将不会出错。
那么,为什么E处出现了错误。这是因为在函数名getPContent前加了const修饰符,意味着该函数返回的值只能是读取,而不能被修改。而E处的content却为char *是可以被修改的,这与const正好相反了,所以出现了错误。解决方法是:在char *前面加上const修饰符,即:
1 const char * content = tc->getPContent(); //E
再去编译运行,这样就不会出现错误了。