100

ああ

#include "logic.h"
...

class A
{
friend ostream& operator<<(ostream&, A&);
...
};

logic.cpp

#include "a.h"
...
ostream& logic::operator<<(ostream& os, A& a)
{
...
}
...

私がコンパイルすると、それは言う:

std :: ostream&logic :: operator <<(std :: ostream&、A&)'は、引数を1つだけ取る必要があります。

何が問題ですか?

4

6 に答える 6

143

問題は、クラス内でそれを定義することです。

a)は、2番目の引数が暗黙的(this)であり、

b)それはあなたがしたいこと、すなわち拡張をしませんstd::ostream

あなたはそれを自由な関数として定義しなければなりません:

class A { /* ... */ };
std::ostream& operator<<(std::ostream&, const A& a);
于 2012-05-24T20:28:53.573 に答える
52

フレンド関数はメンバー関数ではないため、問題は次operator<<のフレンドとして宣言することですA

 friend ostream& operator<<(ostream&, A&);

次に、それをクラスのメンバー関数として定義してみてくださいlogic

 ostream& logic::operator<<(ostream& os, A& a)
          ^^^^^^^

logicクラスなのか名前空間なのか混乱していませんか?

エラーは、2つの引数を取るメンバーを定義しようとしたためです。つまり、暗黙のパラメーターoperator<<を含めて3つの引数を取ることになります。this演算子は2つの引数しかとることができないのでa << b、2つの引数を書くときはabです。

そのクラスとは何の関係もないので、メンバーとしてではなく、メンバー関数ostream& operator<<(ostream&, const A&)として定義したいとします。logic

std::ostream& operator<<(std::ostream& os, const A& a)
{
  return os << a.number;
}
于 2012-05-24T21:13:52.957 に答える
3

テンプレート化されたクラスでこの問題に遭遇しました。これが私が使用しなければならなかったより一般的な解決策です:

template class <T>
class myClass
{
    int myField;

    // Helper function accessing my fields
    void toString(std::ostream&) const;

    // Friend means operator<< can use private variables
    // It needs to be declared as a template, but T is taken
    template <class U>
    friend std::ostream& operator<<(std::ostream&, const myClass<U> &);
}

// Operator is a non-member and global, so it's not myClass<U>::operator<<()
// Because of how C++ implements templates the function must be
// fully declared in the header for the linker to resolve it :(
template <class U>
std::ostream& operator<<(std::ostream& os, const myClass<U> & obj)
{
  obj.toString(os);
  return os;
}

現在:* cppに隠されている場合、toString()関数をインラインにすることはできません。*あなたはヘッダーのいくつかのコードで立ち往生しています、私はそれを取り除くことができませんでした。*演算子はtoString()メソッドを呼び出しますが、インライン化されていません。

operator <<の本体は、friend句またはクラスの外部で宣言できます。どちらのオプションも醜いです。:(

誤解している、または何かが足りないのかもしれませんが、演算子テンプレートを前方宣言するだけではgccにリンクされません。

これも機能します:

template class <T>
class myClass
{
    int myField;

    // Helper function accessing my fields
    void toString(std::ostream&) const;

    // For some reason this requires using T, and not U as above
    friend std::ostream& operator<<(std::ostream&, const myClass<T> &)
    {
        obj.toString(os);
        return os;
    }
}

テンプレート化されていない親クラスを使用してoperator<<を実装し、仮想toString()メソッドを使用すると、ヘッダーでの宣言を強制するテンプレートの問題を回避できると思います。

于 2017-06-23T02:27:18.030 に答える
0

メンバー関数として定義するoperator<<と、非メンバーを使用した場合とは異なる分解構文になりますoperator<<。非メンバーoperator<<は二項演算子であり、メンバーoperator<<は単項演算子です。

// Declarations
struct MyObj;
std::ostream& operator<<(std::ostream& os, const MyObj& myObj);

struct MyObj
{
    // This is a member unary-operator, hence one argument
    MyObj& operator<<(std::ostream& os) { os << *this; return *this; }

    int value = 8;
};

// This is a non-member binary-operator, 2 arguments
std::ostream& operator<<(std::ostream& os, const MyObj& myObj)
{
    return os << myObj.value;
}

だから....どうやって本当に彼らを呼ぶのですか?演算子はいくつかの点で奇妙ですoperator<<(...)。意味をなすように頭の中で構文を書くように挑戦します。

MyObj mo;

// Calling the unary operator
mo << std::cout;

// which decomposes to...
mo.operator<<(std::cout);

または、非メンバーの二項演算子を呼び出そうとすることもできます。

MyObj mo;

// Calling the binary operator
std::cout << mo;

// which decomposes to...
operator<<(std::cout, mo);

これらの演算子をメンバー関数にするときに直感的に動作させる義務はありません。必要に応じて、operator<<(int)メンバー変数を左シフトするように定義できます。コメントの数に関係なく、人々が少し不意を突かれる可能性があることを理解してください。書きます。

最後に、オペレーター呼び出しの両方の分解が有効な場合があります。ここで問題が発生する可能性があり、その会話を延期します。

最後に、二項演算子のように見えるはずの単項演算子を書くのがいかに奇妙であるかに注意してください(メンバー演算子を仮想にすることができるので.....また、このパスを展開して実行しないようにしようとしています...。 )。

struct MyObj
{
    // Note that we now return the ostream
    std::ostream& operator<<(std::ostream& os) { os << *this; return os; }

    int value = 8;
};

この構文は、今では多くのコーダーを苛立たせます。

MyObj mo;

mo << std::cout << "Words words words";

// this decomposes to...
mo.operator<<(std::cout) << "Words words words";

// ... or even further ...
operator<<(mo.operator<<(std::cout), "Words words words");

coutここでチェーンの2番目の引数がどのようになっているのかに注意してください....奇妙な権利ですか?

于 2019-09-26T19:37:24.617 に答える
0

演算子のオーバーロードには、メンバー関数のオーバーロードと非メンバー関数のオーバーロードが含まれますが、これらを混在させることはできません。https://condor.depaul.edu/ntomuro/courses/262/notes/lecture3.html

于 2021-03-25T14:59:09.313 に答える
0

重要なポイントは、フレンド関数として定義されるlogic::前です。operator<<

logic::メンバー関数の前にのみ追加されます。これは、この関数がメンバー関数であることをコンパイラーに通知し、対応するアクセス許可(プライベート関数へのアクセスなど)を付与することに似ていることを理解しています。

言い換えると、@ asaellと@Mortezaが述べたように、「フレンド関数を定義するときは、クラスの名前を使用してフレンド関数の名前をスコープすることはありません」。

したがって、のlogic::前に削除する必要がありoperator<<ます。

于 2021-10-21T14:00:53.893 に答える