※ 引述《d630200x (DOGE)》之铭言:
: 在一般运算子多载中的宣告为下
: 传回型别 operator运算子符号(.....)
: 然而看到比如要多载++前置或者是右移运算子>>时
: 宣告会变成
: 传回型别& operator运算子符号(.....)
: 个人不太能理解这个&的意义,翻来翻去也没有找到解答
首先先确定知道回传的资料型别为 T& 时,& 表示其回传的是 reference (参考)
因此其回传的应为其中一个算子的本尊,而非暂时物件,不然就会无中生有
下去的问题就变成什么时候要传本尊,什么时候要产生暂时物件
这个跟我们期望这个运算子怎么作用有关
以 a + b 的结果来说,回传 a 本尊或 b 本尊都极其不合理.
因为这不只意味着 a + b 计算完之后其结果会存在 a 或 b 上,
也意味着 a + b = 3 这写法是合法的 (你可以试着写写看)
你应该不会期望做完 a + b = 3 之后,是 a 或 b 其中一个会变成 3 吧
可以想成如果每次都回传一个暂时物件表示计算结果是最简单的,T& 反而麻烦
但是这样会遇到一些困难:
1. 语意问题
int a = 3;
int b = 0;
int &c = b = a;
如果我们要让这语法合法的话,b = a 的计算结果,也就是 operator= 必须回传 b 本尊
这造就了基本上所有赋值运算都必须要回传 T&
相对的,因为 ++b 也是种赋值运算
int &c = ++b;
要合法的前提也是 operator++ (pre-) 需要回传 T&
operator++ (post-) 反而是例外,因为其回传值与本尊的值就不一样
int &c = b++; // 这边的 c 参考的会是 +1 之前的 b,要嘛语意不合理,要嘛无中生有
2. 连锁呼叫时的复制问题
当你有一种类别物件支援某种可以连锁呼叫的运算子时,可能会在复制的时候发生问题
例如 cout << a << b << c << d << e;
在语意上是希望达到
cout << a; cout << b; cout << c; cout << d; cout << e;
的效果
这就必须让 operator<< 的回传值与其中一个算子 (cout) 相同
于是我们一方面可能需要回传时每次都复制一次 cout 造成效率问题,
另一方面也许 cout 根本就因为运作特性不能复制.
或者你根本期望他套用在同一个物件上
因此选择回传其中一个算子 (cout) 的本尊 (reference, T&) 是最适当的方式
就结论来说,C++ 并没有严格要求你是不是要回传 reference
运算子多载重要的是让使用者直觉的操作,不要做出不预期的运算
在考量使用者可能的使用情境后,选择最适当的设计