私が取り組んでいるプロジェクトには、以下の_score.h
_で定義されているScore
クラスがあります。私はそれをオーバーロードしようとしているので、_<<
_操作がそれに実行されると、__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.cppの関数宣言から_Score::
_を削除します(メンバーとして宣言しないこと)。
なぜこれが機能するのに、前のコードは機能しないのですか?
御時間ありがとうございます!
[〜#〜]編集[〜#〜]
ヘッダーファイルのオーバーロードへの言及をすべて削除しましたが、次の(そして唯一の)エラーが発生します。 binary '<<' : no operator found which takes a right-hand operand of type 'Score' (or there is no acceptable conversion)
main()のテストで適切なオーバーロードが見つからないのはなぜですか? (インクルードではありません、チェックしました)
以下は完全なスコアです。
_#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
_
注:演算子のオーバーロードに関するよくある質問 をご覧ください。
二項演算子は、左側の引数のクラスまたはフリー関数のメンバーにすることができます。 (割り当てなど、一部の演算子はメンバーでなければなりません。)ストリーム演算子の左側の引数はストリームであるため、ストリーム演算子は、ストリームクラスまたはフリー関数のメンバーでなければなりません。 operator<<
を任意の型に実装する標準的な方法は次のとおりです。
std::ostream& operator<<(std::ostream& os, const T& obj)
{
// stream obj's data into os
return os;
}
メンバー関数ではないことに注意してください。また、const
参照ごとにオブジェクトがストリーミングされることにも注意してください。これは、オブジェクトをストリーミングするためにオブジェクトをコピーする必要がなく、ストリーミングによってオブジェクトを変更する必要もないためです。
場合によっては、クラスのパブリックインターフェイスを介して内部にアクセスできないオブジェクトをストリーミングして、オペレーターがオブジェクトにアクセスできないようにする必要があります。次に、2つの選択肢があります:ストリーミングを行うクラスにパブリックメンバーを入れる
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;
}
+
の演算子オーバーロードを作成して、2つのScore
オブジェクトを互いに追加したり、int
をScore
に追加したりするとします。もう1つは、Score
をint
に追加できるようにするためです。 Score
が最初のパラメーターであるものは、スコアのメンバー関数にすることができます。しかし、int
が最初のパラメーターであるものは、int
のメンバー関数になれませんよね?それを助けるために、あなたはそれらを無料の関数として書くことが許されています。これが、この<<
演算子で起こっていることです。メンバー関数をostream
に追加できないため、無料の関数を作成できます。 Score::
部分を削除すると、それが意味されます。
なぜfriend
にする必要があるのですか?そうではありません。パブリックメソッド(getPoints
およびscoreGetName
)のみを呼び出しています。フレンドオペレーターは、プライベート変数と直接やり取りするのが好きなので、たくさんの友人オペレーターがいます。クラスを保守している人が書いて保守しているので、私がそれをしても大丈夫です。 member-function-vs-free-functionの部分と友達の部分を混同しないでください。
最初のパラメーターとしてScore
を受け取る_operator<<
_を作成しているため、_operator<<
_がメンバー関数である場合にコンパイルエラーが発生します(メソッドが呼び出されるオブジェクト)オン)、最後に追加のパラメーターを指定します。
メンバー関数として宣言されている2項演算子を呼び出す場合、式の左側はメソッドが呼び出されるオブジェクトです。例えば_a + b
_は次のように機能します:
_A a;
B b
a.operator+(b)
_
通常、非メンバーの2項演算子を使用することをお勧めします(場合によっては、たとえば_operator<<
_ for ostream
が唯一の方法です。その場合、_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;
}
_