6

私が調査したところ、cout の出力ストリーム演算子をオーバーロードしたい場合、正しい方法は次のようにすることであることがわかりました。

std::ostream& operator<<(std::ostream& os, const T& obj)

ここで起こっていることは、operator<< が実際には ostream で定義されたフレンド関数であり、それを利用しているためです。しかし、問題は、この関数が ostream でどのように定義されているかということです。この関数は 2 つのパラメーターを取り、2 番目のパラメーターはユーザー定義であるため、そこに何が来るかを推測する方法はありません。

クラス固有のオーバーロードは次のようになります。

std::ostream& operator<<(std::ostream& os, const MyClass& obj)

特にC++にはジェネリッククラス(Javaのオブジェクトなど)がないため、コンパイラ/ライブラリは2番目のパラメーターのジェネリック定義をどのように取得しますか?

4

2 に答える 2

4

C++ 関数はオーバーロードできます。つまり、名前が同じで引数が異なる複数の関数が共存できます。コンパイラは、名前の検索、引数の推定、オーバーロードの解決の 3 つの手順を実行します。その結果、1 つの関数オーバーロードだけがベスト マッチとして生き残ることができます。これらの概念の穏やかな紹介は、Stephan T. Lavavej によるシリーズ Core C++の最初の 3 つのビデオから得ることができます。

一般的なケースは、同じ名前空間内にオーバーロードがSある名前空間N(グローバルな場合もあります) 内のユーザー定義クラスです。operator<<(ostream&, S const&)

namespace N {

class S 
{
    // bla
};

std::ostream& operator<<(std::ostream& os, S& const& obj)
{
    // print in terms of public interface of S
    // (else, deckare this a friend function inside S)
    return os;
}

} // N

int main()
{
    std::cout << S(); // operator<<(ostream&, S const&) is the best match
}

名前の検索は巧妙です。この場合、関数の引数に関連付けられた名前空間を検索する、いわゆる引数依存の検索を通じて機能します。上記のコードでは、これらの名前空間はstd(すべての標準ライブラリ関数が存在Nする場所) と (オーバーロードが存在する場所operator<<(ostream&, S const&)) です。引数推定により正しい型が推定され、オーバーロードの解決により、オーバーロードが最適な一致であることがわかります (この場合、おそらく唯一の一致)。

したがって、「ネイティブ」構文を使用してユーザー定義型を出力する機能。

: この場合、後者は前者と同じ語彙形式を持っていますが、「左シフト」演算子ではなく「ストリーム挿入」演算子と呼ばれます。

于 2014-03-08T20:01:28.333 に答える