无法重载operator <<作为成员函数

19 c++ operator-overloading

我试图operator<<作为成员函数重载.如果只是这样做它的工作原理:

friend ostream& operator<<(ostream& os, const MyClass& myClass); 在我的头文件和我的MyClass.cc文件中:

ostream& operator<<(ostream& os, const MyClass& myClass)
{
   return myClass.print(os);
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我尝试friend取消并使其成为成员函数,那么它抱怨operator<<只能采用一个参数.为什么?

ostream& MyClass::operator<<(ostream& os, const MyClass& myClass)
{
   return myClass.print(os);
}
Run Code Online (Sandbox Code Playgroud)

我在这个问题上读到它不能成为一个成员函数,但不确定为什么?

Jer*_*fin 47

当作为成员函数重载时,a << b被解释为a.operator<<(b),因此它只需要一个显式参数(this作为隐藏参数).

因为这要求重载是用作左操作数的类的一部分,所以它对普通的ostreams等没有用.这需要你的重载成为ostream类的一部分,而不是你的类的一部分.由于您不允许修改ostream,因此您无法执行此操作.这只留下全球超载作为替代.

但是,有一个相当广泛使用的模式,你在全局范围内重载运算符,但是调用成员函数:

class whatever { 
    // make this public, or the global overload a friend.
    std::ostream &write(std::ostream &dest) const { 
        // write self to dest
    }
};

std::ostream &operator<<(std::ostream &os, whatever const &w) { 
     return w.write(os);
}
Run Code Online (Sandbox Code Playgroud)

当/如果您想要多态行为时,这尤其有用.你不能让重载的运算符本身变成多态,但是你调用了virtual它的成员函数,所以无论如何它都是多态的.

编辑:以(我希望)澄清情况,你可以通过几种不同的方式做到这一点.第一个也可能是最明显的是让我们的write成员公开,并让全局运营商调用它.由于它是公开的,我们不需要做任何特殊的事情让操作员使用它:

class myClass {
public:
    std::ostream &write(std::ostream &os) const { 
        // write stuff to stream
        return os;
    }   
};

std::ostream &operator<<(std::ostream &os, myClas const &m) { 
   // since `write` is public, we can call it without any problem.
   return m.write(os);
}
Run Code Online (Sandbox Code Playgroud)

第二种方法是write私有,并声明operator<<朋友给它访问:

class myClass {
    // Note this is private:
    std::ostream &write(std::ostream &os) const { 
        // write stuff to stream
        return os;
    }

    // since `write` is private, we declare `operator<<` a friend to give it access:
    friend std::ostream &operator<<(std::ostream &, myClass const &);
};

std::ostream &operator<<(std::ostream &os, myClas const &m) { 
   return m.write(os);
}
Run Code Online (Sandbox Code Playgroud)

第三种可能性几乎与第二种可能性相似:

class myClass {
    // Note this is private:
    std::ostream &write(std::ostream &os) const { 
        // write stuff to stream
        return os;
    }

    // since `write` is private, we declare `operator<<` a friend to give it access.
    // We also implement it right here inside the class definition though:
    friend std::ostream &operator<<(std::ostream &os, myClas const &m) { 
        return m.write(os);
    }
};
Run Code Online (Sandbox Code Playgroud)

第三种情况在C++中使用了一个名为"名称注入"的相当奇怪(并且鲜为人知)的规则.编译器知道friend函数不能成为类的一部分,因此不是定义成员函数,而是将该函数的名称"注入"到周围的作用域(在本例中为全局作用域).即使operator<<在类定义中定义,它根本不是成员函数 - 它是一个全局函数.


Ben*_*ley 10

您可以operator<<作为成员函数重载.但是你不能写一个operator<<在左侧带有ostream 的成员,而你的班级在右侧.

当你创建一个(非静态)成员函数时,有一个隐含的第一个参数,即调用对象. operator<<是二进制的,所以它只需要2个参数.如果你把它作为一个成员函数,你只能给它一个paremeter,因为它已经有一个(调用对象).由于该调用对象始终是第一个参数,因此您不可能将输出运算符编写为(非静态)成员(至少不是该特定函数的标准形式),因为对于这种情况,ostream需要成为第一个论点.