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ください。これは、ストリーミングするためにオブジェクトをコピーしたくないし、ストリーミングによってオブジェクトが変更されたくないからです。


クラスの public インターフェイスから内部にアクセスできないオブジェクトをストリーミングして、オペレーターがアクセスできないようにしたい場合があります。次に、2 つの選択肢があります。ストリーミングを行うクラスに public メンバーを配置するか

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

+たとえば、2つのScoreオブジェクトを相互に追加できるように、および別のオブジェクトをに追加できるようintScore、3つ目のオブジェクトをに追加できるように、演算子のオーバーロードを記述したいとしScoreますint。aScoreが最初のパラメーターであるものは、Scoreのメンバー関数にすることができます。しかし、anintが最初のパラメーターであるものは、のメンバー関数になることはできませんintよね?それを助けるために、あなたはそれらを無料の関数として書くことが許されています。これがこの演算子で起こっていることです。<<メンバー関数を追加できないostreamため、無料の関数を作成します。それはあなたがその部分を取り除くときそれが意味することですScore::

では、なぜそれが必要なのfriendですか?そうではありません。getPointsパブリックメソッド(および)のみを呼び出していますscoreGetName。彼らはプライベート変数と直接話すのが好きなので、あなたはたくさんの友達演算子を見ます。それらはクラスを維持する人によって書かれ、維持されているので、私はそれをしても大丈夫です。友達の部分をmember-function-vs-free-functionの部分と混同しないでください。

于 2010-05-13T16:10:47.403 に答える
6

最初のパラメーター (メソッドが呼び出されるオブジェクト) としてa を取る を作成し、最後に追加のパラメーターを与えるoperator<<ため、例のメンバー関数である場合にコンパイル エラーが発生します。operator<<Score

メンバー関数として宣言された二項演算子を呼び出す場合、式の左側は、メソッドが呼び出されるオブジェクトです。たとえばa + b、次のように機能します。

A a;
B b

a.operator+(b)

通常、非メンバーの二項演算子を使用することをお勧めします (場合によっては、 operator<<forostreamが唯一の方法です。その場合、a + b次のように動作する可能性があります。

A a;
B b

operator+(a, b);

両方の方法を示す完全な例を次に示します。main() は「55」を 3 回出力します。

#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 に答える