2

シリアライゼーションを行うために「グローバルフレンド演算子のオーバーロード」を宣言しなければならないことは、いつも面倒だと思いました。クラスの外でシリアライゼーション演算子を宣言しなければならないことは、基本的なことではないように思われました。だから私はその理由についての確かな答えを探していました。

(注:すでに書かれた良い答えを見つけるために誰かがより良いGoogle-Fuを持っているなら、私はそれを読むことに興味があります。)

私が疑っているのは、技術的に可能であり、表記上の問題にすぎないということです。ライブラリが<<andのメンバー オーバーロードを行うように設計されてい>>た場合、左から右ではなく、右から左への一連のストリーミング操作を作成する必要があります。したがって、書く代わりに:

Rational r (1, 2);
cout << "Your rational number is " << r;

出力行を次のように記述する必要があります。

r >> ("Your rational number is " >> cout);

>>および<<左から右に関連付けるため、後方連鎖を開始するには括弧が必要です。r >> "Your rational number is "それらがなければ、 before に一致するものを見つけようとします"Your rational number is " >> cout右から左への結合性を持つ演算子が選択されていた場合、これは回避できます。

r >>= "Your rational number is " >>= cout;

(注: ライブラリ内では、文字列リテラルのような非クラス型は、グローバル演算子のオーバーロードで処理する必要があります。)

しかし、それが限界なのでしょうか? クラスにシリアライゼーションをディスパッチする必要がある iostream スタイルの設計では、この逆転はほとんど避けられないのでしょうか? 私は他の問題を見逃していますか?


更新おそらく「問題」のより良い言い回しは、私が次のことを疑うようになったと言うことです:

自分自身をシリアライズしたい非ストリーム オブジェクトの場合、iostream ライブラリは、挿入子と抽出子がグローバル オーバーロードの代わりにクラス メンバーになるように、仮説的に設計されている可能性があります...そしてランタイム プロパティに (大幅に) 影響を与えません。しかし、これは、iostream の作成者がクライアントに右から左へのストリーミング操作を強制することを受け入れる意思がある場合にのみ機能します。

しかし、オペレーターとメンバーをグローバルにオーバーロードすることで、(右から左ではなく) 左から右に自分自身を表現する、それ以外の場合はロック解除可能な機能をロック解除できる理由について、私は直観に欠けています。問題は、後知恵、テンプレート、または C++11 のいくつかの難解な機能が代替手段を提供できるかどうかです。または、「C ++の物理学」には、ある方向に対して別の方向に固有のバイアスがあり、グローバルなオーバーロードは、それをオーバーライドするための本で唯一のコンパイル時のトリックです。

モーターのフレミングの左手の法則と比較

4

5 に答える 5

3

ストリーム演算子のオーバーロードについては、メンバーであるか非メンバーであるかについて標準によって課せられる制限がないため、理想的には可能です。実際、標準ライブラリで定義されているストリームの出力および入力演算子のほとんどは、ストリームのメンバーです。クラス。

理論的根拠:

なぜinsertersextractorsメンバー関数としてオーバーロードされないのですか?

通常、演算子のオーバーロードのルールは次のとおりです。

二項演算子が左のオペランドを変更する場合は、通常、左のオペランドの型のメンバー関数にするのが便利です(通常、オペランドのプライベートメンバーにアクセスする必要があるため)。

この規則により、ストリーム演算子は、左側のオペランドの型のメンバーとして実装する必要があります。ただし、それらの左側のオペランドは標準ライブラリからのストリームであり、標準ライブラリのストリームタイプを変更することはできません。したがって、カスタムタイプに対してこれらの演算子をオーバーロードする場合、これらは通常、非メンバー関数として実装されます。

于 2011-10-22T19:45:16.267 に答える
2

表示しているオブジェクトから << と >> の定義を分離することで、より柔軟になります。

まず、列挙型やポインターなどの非クラス型をカスタム表示したい場合があります。クラス Foo があり、Foo へのポインターをカスタム印刷したいとします。Fooにメンバー関数を追加することではできません。または、テンプレート化されたオブジェクトを表示したいが、特定のテンプレート パラメータについてのみ表示したい場合があります。たとえば、vector<int> をカンマ区切りのリストとして表示し、vector<string> を文字列の列として表示したい場合があります。

もう 1 つの理由は、既存のクラスを変更することが許可されていない、または変更する意志がないことです。これは、OO 設計におけるオープン/クローズの原則の良い例です。クラスを拡張用にオープンにし、変更用にクローズする必要があります。もちろん、クラスはカプセル化を壊さずにその実装の一部を公開する必要がありますが、多くの場合はそうです (ベクトルは要素を公開し、複合体は Re と Im を公開し、文字列は c_str を公開するなど)。

理にかなっていれば、異なるモジュールの同じクラスに対して << の 2 つの異なるオーバーロードを定義することもできます。

于 2011-10-23T20:05:27.503 に答える
2

以前も同じ質問がありましたが、インサータとエクストラクタはグローバルである必要があるようです。私にとっては問題ありません。クラスでこれ以上「友達」関数を作成しないようにしたいだけです。これが私が行う方法です。つまり、「<<」が呼び出すことができるパブリック インターフェイスを提供します。

class Rock {
    private:
        int weight;
        int height;
        int width;
        int length;

    public:
        ostream& output(ostream &os) const {
            os << "w" <<  weight << "hi" << height << "w" <<  width << "leng" << length << endl;
            return os;
        }
    };

    ostream& operator<<(ostream &os, const Rock& rock)  {
        return rock.output(os);
    }
于 2013-06-16T01:09:58.197 に答える
1

私は他の問題を見逃していますか?

私が考えることができるわけではありませんが、それはすでにかなり悪いと思います.

通常outfile << var1 << var2 << var3;は、かなり「線形」な構文です。また、どちらの場合も左から右に読むため、名前はファイル内と同じ順序になります。

構文を非線形にすることを計画しています。人間の読者は、何が起こっているのかを確認するためにスキップして戻ってくる必要があります。これはそれを難し​​くします。そして、あなたはさらに先へ進みます。最後の行を読むには、r >>= "Your rational number is " >>= cout;最初に >>= を読み進めて、最後の単語 (またはその付近) までスキップする必要があることを確認し、">>= cout" を読み、文字列の先頭までスキップして、文字列を順方向に読み取ります。あるトークンから次のトークンに目を動かすのとは対照的に、脳はプロセス全体をパイプライン処理できます。

私は、このような非線形構文を持つ言語で数年の経験があります。私は現在、clang を使用して C++ をその言語に「コンパイル」することを検討しています。(それ以外にも理由はありますが。)うまくいけば、私ははるかに幸せになります。

私の好ましい代替手段は、メンバー関数のみを呼び出す非常に最小限の演算子のオーバーロードです。少しでも最適化すると、とにかく生成された実行可能ファイルから消えます。

上記には「明らかな」例外が 1 つあります。myobj >> cout;

于 2011-10-22T22:52:55.613 に答える
1

C++ では、二項演算子は一般に非クラス メンバーです。Bjarne Stroustrup operator+によるThe C++ Programming Languageによると、正規表現は、最初に左のオペランドをコピーし、次に右のオペランドで += を使用して結果を返すグローバル関数です。したがって、ストリーム演算子をグローバルにすることは、まったく異常ではありません。Als が述べたように、ストリーム オペレータはデータ クラスではなくストリーム クラスのメンバーであることが期待されます。

于 2011-10-24T03:25:55.773 に答える