最近在复习C++的时候遇到了一些比较容易混淆的概念,其中就包括函数返回值的问题。让我们看一下下面这几个函数:
class CMyString {...};
CMyString& CMystring::operator =(const CMyString &str);//函数①
class Rational {...};
const Rational Rational::operator* (const Rational& lhs, const Rational& rhs);//函数②
//函数②
class TextBlock {
public:
...
const char& operator[](std::size_t position) const
{ return text[position]; }//函数③
char& operator[](std::size_t position)
{ return text[position]; }//函数④
private:
std::string text;
};
关于函数①:
作为赋值运算符的重载,如果返回值不是reference to CMyString 而是CMyString,那会产生什么结果?假设有三个CMyString的实例,那么该语句:
str1 = str2 = str3;
就无法通过编译。
因为,如果函数的返回类型是个内置类型,那么改动函数返回值从来就不合法。纵使合法,C++以by value返回对象这一事实意味被改动的其实是str1 = str2的一个副本,不是str1 = str2自身,这不是我们想要的结果。
同样的理由也可以解释函数③及函数④为什么要返回一个引用,不然的话
TextBlock tb("Hello");
tb[0] = 'x';
第二句赋值语句也是不合法的。
关于函数②:
将返回值设为const则相反,是为了避免有人“无意识地赋值”。比如说接下来这个例子:
Rational a, b, b;
...
(a * b) = c; // 在a * b的成果上调用operator=
这种诡异的情况多发生在:
if (a * b = c) ... //应该每个人都这么干过
所以为了避免这种情况,能使用const的时候尽量使用const。
函数③:
有同学应该就会问了,函数①返回引用是为了二次赋值,函数②返回const是为了避免二次赋值,那函数③返回const的引用又是什么鬼?!
这里就涉及另一种情况了,即对const对象的操作。
请看以下代码:
class object{
public:
char getMember{ return p };
private:
char p;
};
void test(const object & parm){
char temp = parm.getMember();
}
// 编译错误,error C2662: 'object::getMember' : cannot convert 'this' pointer from 'const object' to 'object &'
原因在于函数的参数是一个pass by reference-to-const(插一句,这是一个广泛使用的技术,首先这样避免了调用复制构造函数,提高了效率、其次避免了参数被莫名其妙地修改),而只有const成员函数可以作用于const对象。
函数④:
函数④就很好理解了,即对non-const对象进行操作。同样函数④也需要考虑被赋值的情况,所以需要返回一个引用。函数③和函数④可以用下面这一段代码来加深理解:
TextBlock tb("Hello");
std::cout << tb[0]; //调用 non-const TextBlock::operator[]
const TextBlock ctb("World");//调用const TextBlock::operator[]
std::cout<< ctb[0];
本篇博客的例子及知识点来自《Effective C++》以及《剑指Offer》,如有不完善的地方还请联系我,多谢!