40

在我正在进行的一个项目中,我有一个Score类,在下面定义score.h。我试图重载它,因此,当<<对其执行操作时,_points + " " + _name会打印出来。

这是我试图做的:

ostream & Score::operator<< (ostream & os, Score right)
{
    os << right.getPoints() << " " << right.scoreGetName();
    return os;
}

以下是返回的错误:

score.h(30) : error C2804: binary 'operator <<' has too many parameters

(这个错误实际上出现了 4 次)

我设法通过将重载声明为友元函数来使其工作:

friend ostream & operator<< (ostream & os, Score right);

Score::从 score.cpp 中的函数声明中删除(实际上没有将其声明为成员)。

为什么这行得通,而前一段代码却行不通?

谢谢你的时间!

编辑

我删除了对头文件重载的所有提及...但是我收到以下(也是唯一的)错误。binary '<<' : no operator found which takes a right-hand operand of type 'Score' (or there is no acceptable conversion) 为什么我的测试在 main() 中找不到合适的重载?(这不是包含,我检查过)

下面是完整的分数.h

#ifndef SCORE_H_
#define SCORE_H_

#include <string>
#include <iostream>
#include <iostream>

using std::string;
using std::ostream;

class Score
{

public:
    Score(string name);
    Score();
    virtual ~Score();
    void addPoints(int n);
    string scoreGetName() const;
    int getPoints() const;
    void scoreSetName(string name);
    bool operator>(const Score right) const;

private:
    string _name;
    int _points;

};
#endif
4

3 回答 3

80

注意:您可能想查看运算符重载 FAQ


二元运算符既可以是其左侧参数类的成员,也可以是自由函数。(某些运算符,如赋值,必须是成员。)由于流运算符的左侧参数是流,因此流运算符要么必须是流类的成员,要么是自由函数。实现operator<<任何类型的规范方法是:

std::ostream& operator<<(std::ostream& os, const T& obj)
{
   // stream obj's data into os
   return os;
}

请注意,它不是成员函数。另请注意,它需要对象按const引用进行流式传输。那是因为您不想复制对象以便对其进行流式传输,并且您也不希望流式传输更改它。


有时您希望流式传输其内部无法通过类的公共接口访问的对象,因此操作员无法获取它们。然后你有两个选择:要么将一个公共成员放入进行流式传输的类中

class T {
  public:
    void stream_to(std::ostream&) const {os << obj.data_;}
  private:
    int data_;
};

并从运营商那里调用:

inline std::ostream& operator<<(std::ostream& os, const T& obj)
{
   obj.stream_to(os);
   return os;
}

或使操作员friend

class T {
  public:
    friend std::ostream& operator<<(std::ostream&, const T&);
  private:
    int data_;
};

以便它可以访问类的私有部分:

inline std::ostream& operator<<(std::ostream& os, const T& obj)
{
   os << obj.data_;
   return os;
}
于 2010-05-13T16:04:00.090 回答
9

假设您想编写一个运算符重载 for+以便可以将两个Score对象相互添加,另一个对象可以将 an 添加int到 a Score,第三个对象可以将 a 添加Score到 an int。aScore是第一个参数的那些可以是 Score 的成员函数。但是 anint是第一个参数的那个不能成为 的成员函数int,对吧?为了帮助您,您可以将它们编写为自由函数。这就是这个<<运算符发生的事情,你不能添加一个成员函数,ostream所以你写了一个自由函数。这就是你拿走Score::零件的意思。

现在为什么它必须是一个friend?它没有。您只调用公共方法(getPointsscoreGetName)。您会看到很多友元运算符,因为他们喜欢直接与私有变量对话。我可以这样做,因为它们是由维护班级的人编写和维护的。只是不要让朋友部分与成员函数与自由函数部分混淆。

于 2010-05-13T16:10:47.403 回答
6

当 is 示例中的成员函数时,您会遇到编译错误,operator<<因为您正在创建一个operator<<将 aScore作为第一个参数(调用该方法的对象),然后在最后给它一个额外的参数。

当您调用声明为成员函数的二元运算符时,表达式的左侧是正在调用该方法的对象。例如a + b可能像这样工作:

A a;
B b

a.operator+(b)

通常最好使用非成员二元运算符(在某些情况下 - 例如operator<<forostream是唯一的方法。在这种情况下,a + b可能会像这样工作:

A a;
B b

operator+(a, b);

这是一个完整的示例,显示了两种方法;main() 将输出 '55' 三次:

#include <iostream>

struct B
{
    B(int b) : value(b) {}
    int value;
};


struct A
{
    A(int a) : value(a) {}
    int value;

    int operator+(const B& b) 
    {
        return this->value + b.value;
    }
};

int operator+(const A& a, const B& b)
{
    return a.value + b.value;
}

int main(int argc, char** argv)
{
    A a(22);
    B b(33);

    std::cout << a + b << std::endl;
    std::cout << operator+(a, b) << std::endl;
    std::cout << a.operator+(b) << std::endl;

    return 0;
}
于 2010-05-13T16:25:19.587 回答