为啥重载输入输出运算符必须是非成员函数

cout \u0026lt;\u0026lt; XXX 这种情况是cout在调用operator\u0026lt;\u0026lt;而不是XXX在调用operator\u0026lt;\u0026lt; 。如果你要把operator\u0026lt;\u0026lt;设为成员函数就只能用 XXX \u0026lt;\u0026lt; cout 这种形式。
■网友
作为成员函数的话,左操作数非得是自己不可
■网友
首先肯定是可以的, 只要你不嫌写法反人类, 比如下面这种
struct point{ int x; int y; point (int _x, int _y) : x(_x), y(_y) {} std::ostream\u0026amp; operator\u0026lt;\u0026lt;(std::ostream\u0026amp; os) const { os \u0026lt;\u0026lt; "(" \u0026lt;\u0026lt; x \u0026lt;\u0026lt; ", " \u0026lt;\u0026lt; y \u0026lt;\u0026lt; ")"; return os; }};int main(int argc, const char* argv){ point p1(1, 2); p1 \u0026lt;\u0026lt; std::cout; // 写法同p1.operator\u0026lt;\u0026lt;(std::cout); return 0;}输出如下:
(1, 2)
如果你这个写法能接受, 无非就是对象和std::cout调换了位置, 那么请看接下来的内容, 输出多个对象
int main(int argc, const char* argv){ point p1(1, 2); point p2(2, 3); point p3(3, 4); // p3 \u0026lt;\u0026lt; p2 \u0026lt;\u0026lt; p1 \u0026lt;\u0026lt; std::cout; // build error ! p3 \u0026lt;\u0026lt; (p2 \u0026lt;\u0026lt; (p1 \u0026lt;\u0026lt; std::cout)); // ok ! return 0;}输出如下:
(1,2)(2,3)(3,4)
这个就不是习惯的问题了, 因为运算优先级的问题, 同时操作多个对象的输入输出就会是一个非常反人类的行为, 原因在上面有人已经提到了 @573xmcgcg
一言以蔽之
想达到符合习惯的写法(std::ostream \u0026lt;\u0026lt; obj)一定是让标准io的对象调用你自定义对象的operator, 调用者为标准io库的对象, 调用的参数是你自定义对象的operator
想达到把自定义对象的输入输出操作符封装到对象内部(作为成员变量), 一定是让你自定义对象的operator调用标准io的对象, 调用者为你自定义对象的operator, 调用的参数是标准io库的对象
书上完整的意思是说:
让你重载标准io库中的函数operator\u0026lt;\u0026lt;()
针对std::ostream \u0026lt;\u0026lt; XXX这种调用方式的调用主体是std::ostream的对象, 如果想把操作符搞成成员函数那也是在标准io库里改代码, 而不是改你的代码, 标准io库中对内置类型都有支持, 比如下面这些, 如果想让其支持你的类型, 除非你把你的类型加到标准io库中并重新build一份出来
operator\u0026lt;\u0026lt;(__ostream_type\u0026amp; (*__pf)(__ostream_type\u0026amp;)) operator\u0026lt;\u0026lt;(__ios_type\u0026amp; (*__pf)(__ios_type\u0026amp;)) operator\u0026lt;\u0026lt;(ios_base\u0026amp; (*__pf) (ios_base\u0026amp;)) * All the @c operator\u0026lt;\u0026lt; functions (aka \u0026lt;em\u0026gt;formatted output operator\u0026lt;\u0026lt;(long __n) operator\u0026lt;\u0026lt;(unsigned long __n) operator\u0026lt;\u0026lt;(bool __n) operator\u0026lt;\u0026lt;(short __n); operator\u0026lt;\u0026lt;(unsigned short __n) operator\u0026lt;\u0026lt;(int __n); operator\u0026lt;\u0026lt;(unsigned int __n) operator\u0026lt;\u0026lt;(long long __n) operator\u0026lt;\u0026lt;(unsigned long long __n) operator\u0026lt;\u0026lt;(double __f) operator\u0026lt;\u0026lt;(float __f) operator\u0026lt;\u0026lt;(long double __f) operator\u0026lt;\u0026lt;(const void* __p) operator\u0026lt;\u0026lt;(__streambuf_type* __sb); operator\u0026lt;\u0026lt;(basic_ostream\u0026lt;_CharT, _Traits\u0026gt;\u0026amp; __out, _CharT __c) operator\u0026lt;\u0026lt;(basic_ostream\u0026lt;_CharT, _Traits\u0026gt;\u0026amp; __out, char __c) operator\u0026lt;\u0026lt;(basic_ostream\u0026lt;char, _Traits\u0026gt;\u0026amp; __out, char __c) operator\u0026lt;\u0026lt;(basic_ostream\u0026lt;char, _Traits\u0026gt;\u0026amp; __out, signed char __c) operator\u0026lt;\u0026lt;(basic_ostream\u0026lt;char, _Traits\u0026gt;\u0026amp; __out, unsigned char __c) operator\u0026lt;\u0026lt;(basic_ostream\u0026lt;_CharT, _Traits\u0026gt;\u0026amp; __out, const _CharT* __s) operator\u0026lt;\u0026lt;(basic_ostream\u0026lt;_CharT, _Traits\u0026gt;\u0026amp; __out, const char* __s); operator\u0026lt;\u0026lt;(basic_ostream\u0026lt;char, _Traits\u0026gt;\u0026amp; __out, const char* __s) operator\u0026lt;\u0026lt;(basic_ostream\u0026lt;char, _Traits\u0026gt;\u0026amp; __out, const signed char* __s) operator\u0026lt;\u0026lt;(basic_ostream\u0026lt;char, _Traits\u0026gt;\u0026amp; __out, const unsigned char* __s) operator\u0026lt;\u0026lt;(basic_ostream\u0026lt;_CharT, _Traits\u0026gt;\u0026amp;\u0026amp; __os, const _Tp\u0026amp; __x)


推荐阅读