const修饰的成员函数引发的一个编译错误


头文件 request.h

   
  #include <string>
  
#include <map>
using namespace std;
namespace mss {
class Request {
typedef map<string,string> ParameterMap;
typedef ParameterMap::iterator Parameter_itr;
public:
virtual string& GetParameter(const string& key) const;
private:
ParameterMap m_parameter;
};
}

实现文件request.cpp

   
  #include <map>
  
#include "request.h"
using namespace mss;
using namespace std;
string& Request::GetParameter(const string& key) const {
return m_parameter.find(key)->second;
}
}

GCC编译报的错误是。error: invalid initialization of reference of type 'std::string&' from expression of type 'const std::basic_string<char, std::char_traits<char>, std::allocator<char> >'|
但是我只要把const去掉.
virtual string& GetParameter(const string& key);
这种形式就可以编译通过。另外一种方式就是改成
virtual const string& GetParameter(const string& key) const ;
也可以编译通过。
求解释。const 成员函数 除了不能修改成员之外,还有什么其他特殊的地方?

gcc C++

lilimu 12 years, 4 months ago

这个原理很简单,map的find函数被重载了,有两种形式:

   
  _Iter map::find(const _KeyType &key);
  
_Const_Iter map::find(const _KeyType &key) const;

两个的返回值是不一样的,一个返回iterator,一个返回const_iterator。const_iterator和iterator的差别在于,const_iterator有点类似于const指针,返回的对象是带有const修饰的;所以const_iterator->second一定是返回一个const string&,而不是string&
而编译器匹配这两个函数的时候有个顺序,如果调用的map是const的map,那就匹配第二个;否则优先匹配第一个。因为你的函数定义成了const,所以当前的this指针其实是const Request *;所以this->m_parameter类型是const map<string,string>,因此只能匹配第二个。这就是编译出错的原因。

解决方法的话,你可以学着STL里面的样子,也定义两个版本:

   
  virtual string& GetParameter(const string& key);
  
virtual const string& GetParameter(const string& key) const ;

这样既保证了const的时候可以实现相应的功能,非const的时候也能返回一个可以修改的引用。

总结来说,const成员函数最本质的作用在于,隐含的this指针的类型变成了const someclass 而不是someclass

题外话:
find找不到的时候那个函数会崩溃(在->second的地方),这个应该处理一下吧……

我檫嘞闹不住蘑 answered 12 years, 4 months ago

Your Answer