今天在写代码的时候,发现添加了下面的这个函数(update)之后,怎么都编译通不过。大概的原始代码如下:
#include<iostream>
#include<string>
using namespace std;
class SyncScheduler
{
public:
SyncScheduler(string name):_name(name){}
string& getName() { return _name; }
private:
string _name;
};
void update(const string& name)
{
cout<<name<<endl;
}
void foo(const SyncScheduler& ss)
{
return update(ss.getName());
}
int main()
{
SyncScheduler ss("helloworld");
foo(ss);
system("pause");
return 0;
}
编译器提示下面错误:
main.cpp(22): error C2662: “SyncScheduler::getName”: 不能将“this”指针从“const SyncScheduler”转换为“SyncScheduler &”
1> 转换丢失限定符
尝试了几种方法后,最后只有将getName函数前后都加上const修饰符后,编译才能通过。
const string& getName() const { return _name; }
这是什么原因呢?查阅了相关资料后,发现了一些线索。
"在C++中可以传对象引用,比用指针方便,但是为了避免在函数中对象被修改,需要加const限定符,相应的,在实现对象的成员函数时,也要添加const,这样,因为只有const成员函数才能被const对象调用。"
先举例说明:
class File
{
public:
File(string filename,string filepath):_filename(filename),_filepath(filepath) { }
const string getFileName() const {return this->_filename;}
string getFilePath() const {return this->_filepath;}
private:
string _filename;
string _filepath;
};
void test(const File& f)
{
cout<<"filename is:"<<f.getFileName()<<endl;
cout<<"filepath is:"<<f.getFilePath()<<endl;
}
int main()
{
File f("a.out","/root");
test(f);
system("pause");
return 0;
}
从上可看到,成员函数前面的const是可选的,但是其后面的const是必须的。如果去掉getFilePath函数后面的const修饰符,编译器会给出下面错误:
error C2662: “File::getFilePath”: 不能将“this”指针从“const File”转换为“File &”
这是因为:const File& f 相当于一个const对象。由于const对象在调用成员函数的时候,会将this指针强制转换为const this,所以它将无法找到相应的const getFilePath()函数,并且编译器也无法将一个const的对象转换为一个普通对象来调用这个普通方法getFilePath()。
那SyncScheduler::getName()函数为何必须在前面加const修饰符呢?先看下面代码:
class File
{
public:
File(string filename,string filepath):_filename(filename),_filepath(filepath) { }
const string getFileName() const {return this->_filename;}
string getFilePath() const {return this->_filepath;}
private:
string _filename;
string _filepath;
};
void test1(const string& str)
{
cout<<"test1 :"<<str<<endl;
}
void test2(const string str)
{
cout<<"test2 :"<<str<<endl;
}
int main()
{
File f("a.out","/root");
test1(f.getFileName());
test2(f.getFileName());
test1(f.getFilePath());
test2(f.getFilePath());
const string& ss = f.getFilePath();
cout<<"ss is:"<<ss<<endl;
system("pause");
return 0;
}
运行结果如下:
test1 :a.out
test2 :a.out
test1 :/root
test2 :/root
ss is:/root
Press any key to continue . . .
在上面的结果中可看出,函数前面的const是非必须的。但是,为何SyncScheduler::getName()需要呢。不同之处在于getName返回的是一个引用!为了确保成员_name不会被改变,它的引用者必须也是const类型的。