超载左移操作员

时间:2014-03-08 19:40:26

标签: c++ operator-overloading argument-dependent-lookup

我已经研究过并发现当你想为cout重载输出流操作符时,那么正确的方法是这样做:

std::ostream& operator<<(std::ostream& os, const T& obj)

这个函数必须在类之外定义,因为这里发生的是运算符&lt;&lt;实际上是在ostream中定义的友元函数,你正在利用它。但是,问题是,这个函数究竟是如何在ostream中定义的?由于此函数需要2个参数,而第二个参数是用户定义的,因此他们无法猜出将要发生什么。

特定类的重载应如下所示:

std::ostream& operator<<(std::ostream& os, const MyClass& obj)

编译器/库如何为第二个参数采用泛型定义,特别是因为在C ++中没有泛型类(如Java中的Object)这样的东西?

2 个答案:

答案 0 :(得分:6)

我觉得你很困惑:

  

运营商&lt;&lt;实际上是ostream中定义的友元函数,你正在利用它。

operator <<内定义 class std::ostream是正确的。实际上,它内部定义了几个版本。但那些与我们无关。此外,它们不是friend函数:根据定义,friend函数在之外定义它所属的类。

但这与您定义的函数无关,因为您的operator <<函数是单独的重载,当您将类型的对象作为第二个参数传递给调用<<(第一个参数为std::ostream&)。

正如TemplateRex所解释的那样,找到适当函数的确切方法是通过参数依赖查找。但更基本的是,您只需要知道有两种方法可以为给定的参数类型AB定义二元运算符:

  • 作为类A内的成员函数,并且只有一个B类型的参数
  • 作为具有两个参数的自由函数,类型为AB

使用运算符时,这两个定义都是候选函数。 (但是有几个运算符,例如复制赋值只能在类中定义,而不能在外部定义)。所以,回到你的问题:

  

这个函数究竟是如何在ostream中定义的?由于此函数需要2个参数,而第二个参数是用户定义的,因此他们无法猜出即将发生的事情

答案是在ostream中定义 。唯一的定义是你的,它在外面。

答案 1 :(得分:2)

C ++函数可以重载,即具有相同名称但采用不同参数的多个函数可以共存。编译器经历了名称查找,参数 - 演绎和过载分辨率的三步过程。最后,只有一个函数重载可以作为最佳匹配存活。可以从系列Core C++ by Stephan T. Lavavej中的前三个视频中轻轻地介绍这些概念。

一个常见的情况是命名空间S(可能是全局的)中的用户定义的类N,在同一命名空间内有operator<<(ostream&, S const&)重载。

namespace N {

class S 
{
    // bla
};

std::ostream& operator<<(std::ostream& os, S& const& obj)
{
    // print in terms of public interface of S
    // (else, deckare this a friend function inside S)
    return os;
}

} // N

int main()
{
    std::cout << S(); // operator<<(ostream&, S const&) is the best match
}

名称查找是微妙的,在这种情况下,它通过所谓的参数依赖查找来工作,它查找与函数参数关联的名称空间。对于上面的代码,这些命名空间是std(所有标准库函数都存在)和N(您的重载operator<<(ostream&, S const&)所在的位置)。参数推导将推导出正确的类型,并且重载决策将发现您的重载是最佳匹配(在这种情况下,很可能是唯一的匹配)。

因此,能够使用“本机”语法打印用户定义的类型。

注意:在这种情况下,它不被称为“左移”运算符而是“流插入”运算符,即使后者具有与前者相同的词法形式。