14

我的意思是,我试图在类中重载 operator<<

像这样

 class A {
      public:
           ostream &operator<<(ostream &os);// which doesnt work

      private:
           friend ostream &operator<<(ostream &os, const A& a); //Works
           int i;

 };

  Definition
          ostream &operator<<(ostream &os, const A& a) {
              os<<a.i;
              return os;
          }

为什么我不能在特定于类的类中重载运算符?还是我错过了什么?或者我是否愚蠢地以这种方式思考?请指教。

4

3 回答 3

31

问题是您operator<<会将ostream其作为第二个参数,而不是第一个参数。这样,您可以这样做,但它看起来不直观,并且由于左关联myObject << std::cout,您将无法链接调用。operator<<

将运算符声明为友元而不是成员函数的另一个好处是可以进行自动转换。这意味着如果您有一个B不是派生自A但确实有B(A const&)构造函数的类,您仍然可以将std::cout << my_b;其转换为 anA然后打印。

幸运的是,operator<<如果您愿意,可以在课堂上定义为朋友。你的代码可以写成

class A {
    int i;
    friend std::ostream& operator<<(std::ostream& o, A const& a) {
        o << a.i;
        return o;
    }
};

为什么标准不允许您指定论点应该在哪一边?让我们假设它确实如此,并添加left_ofandright_of关键字来指定:

struct B;

struct A {
     A left_of operator+(B const&) {
         return *this;
     }
};

struct B {
     B right_of operator+(A const&) {
         return *this;
     }
};

当我们这样做时,现在会发生什么A a; B b; f(a + b);?每个类都有一个处理这种情况的运算符,这意味着我们无法决定。由于转换的可能性,看到尽可能多的运算符应该是朋友,不允许这种事情不是什么大问题,并且可以防止这种歧义。(当然,你也可以定义一个成员运算符和一个自由运算符,这会导致非常相似的问题。)

顺便说一句,你的定义friend operator<<没有返回任何东西,这会弄乱链接。

于 2012-02-19T17:03:57.987 回答
27

成员函数:

ostream &operator<<(ostream &os);

确实有效,但不适用于您想要的情况。当您执行以下操作时将调用它:

A a;
a << std::cout;

即对象是运算符的左侧。

于 2012-02-19T17:04:37.823 回答
2

请记住,对于类的非静态成员函数,第一个参数是 this 指针。所以你的“operator<<”函数的签名,编译后将变为:

ostream &operator<<(A *this, ostream &os);

当您执行以下操作时,这将起作用:

A obj;
obj << std::cout;

将“obj”视为第一个参数,将“std::cout”视为运算符“<<”的第二个参数。

重载“<<”的更好方法是使用友元函数,因为这样可以使重载的运算符具有关联性。

于 2018-04-03T12:08:51.373 回答