今天我试图了解与运算符<< 及其重载相关的事情。
让我们来看看这段代码:
cout.operator<<("hello"); // +16 overloads -> implicit conversion to void*
cout.operator<<(123); // +16 overloads
operator<<(cout,"hello"); // +13 overloads
operator<<(cout, 123); // ERROR: no overload
cout << "hello"; // +13 overloads ---> non-member version!
cout << 123; // +16 overloads ---> member version!
感谢Visual Studio的Intellisense,我可以检测到它可以提供多少重载。
我得出结论:
我收到了以下问题:
从最后两行可以看出,当使用带有const char []的cout时,会选择非成员重载。
另外,在第四行我们得到一个错误,因为没有非成员运营商&lt;&lt;带整数的重载。
最后但并非最不重要
cout << “hello”
选择运营商的非会员版本&lt;&lt; ?可能是因为有一个特定的非成员运营商&lt;&lt; overload 是const char [] 的一个很好的候选者,而不是成员运算符&lt;&lt;过载需要 void * ?
答案 0 :(得分:3)
为什么
operator<<
对象的成员cout
需要const char[]
?
字符串分开处理。为std::basic_string
创建成员运算符将要求所有流都具有std::basic_string
功能的依赖性,这并不总是可取的。所有成员运算符都是内置语言类型,但std::basic_string
是一个类,因此它具有非成员运算符重载。有人可能会说const char[]
(衰变到const char*
)是内置类型,但operator<<
流const char*
与std::basic_string
类似,并且它没有&# 39;将这些实现拆分到库的两个不同区域是有意义的。处理字符串的功能(无论是使用数组还是类)通常组合在一起。
为什么没有非会员运营商&lt;&lt;需要一个整数?
因为不需要成为一个人。它已作为成员运营商存在。您不应该直接调用成员运算符(除非您需要,而您的示例不是)。您应该正常使用运算符(stream << ...
)并让重载决策根据参数,作用域等选择正确的成员或非成员运算符。如果您考虑它,非成员重载将导致一个ambiquity错误。 stream << 123
应该stream.operator<<(123)
还是::operator<<(stream, 123)
?只能有一个选择,否则编译失败。
为什么
cout << “hello”
选择operator<<
的非会员版本? 也许是因为有一个特定的非成员operator<<
重载,它是const char[]
的良好候选者,而不是成员 -operator<<
重载,它需要{ {1}}?
这就是原因。类型化void*
参数更适合窄字符串文字,然后是无类型const char[]
指针。因此,如果两个运算符都在范围内(并且void*
重载仅在范围内,如果使用const char[]
),则编译器将选择更好的匹配重载。
答案 1 :(得分:2)
const char *
超载的非成员性是由于技术原因:委员会希望宽字符流也提供const char*
输出,但如果同时提供operator<<(const charT*)
和operator<<(const char *)
bool TestCirclesCollision(double x1, double y1, double r1, double x2, double y2, double r2)
{
// Pythagorean theorem to compute distance between two points
var dx = x2 - x1;
var dy = y2 - y1;
var distance = Math.Sqrt(dx * dx + dy * dy);
// compare to combined radii of two circles
// return true if collision, otherwise false
return distance <= r1 + r2;
}
作为成员,那么由于具有相同签名的两个成员函数,窄字符流将是格式错误的。将它们作为非成员解决了这个问题 - 他们现在只是在重载决策中解决它,如果存在歧义,你只需添加一个更专业的重载。
答案 2 :(得分:1)
为什么没有成员运营商&lt;&lt;对于带有const char []的cout对象?
没有必要,因为const char[]
会衰减到const char*
。
为什么没有非会员运营商&lt;&lt;需要一个整数?
在ADL期间,这不会让我们产生歧义吗?
为什么cout&lt;&lt; “hello”选择运算符的非成员版本&lt;&lt; ?
因为它比转换为void const*
更好,因此需要进行类型转换。