11

だから、いくつかのSOの質問と回答を読んだ後、私はまだなぜ使用するのか理解していません

friend bool operator==( BaseClass const &left, BaseClass const &right )

それ以外の

bool operator==( BaseClass const &right )

今、私はこのhttp://pastebin.com/pKsTabC0 (修正済み)のようなものを持っています-そしてそれはうまくいくようです。しかし、多分私は何かが欠けていますか?助言がありますか?

アップデート1

わかりました。ソースを変更して、正しく機能するようにしましたhttp://ideone.com/fIAmB。不要な仮想を削除し、constを追加しました。それでも私は友達を使う理由がわかりません...

4

4 に答える 4

10

派生関数には親演算子と同じシグネチャがないため、親の比較をオーバーライドするのではなく非表示にします。これは、左側の引数の静的タイプが呼び出される関数を決定するため、とにかく仮想性を利用できないことを意味します。

そのため、仮想比較の通常のメソッドは、基本クラスの仮想比較関数にディスパッチする非メンバーの等式演算子です。

代わりに使用できる代替設計があるのは設計臭かもしれないので、仮想比較の特定の必要性を考慮してください。

また、メンバー比較(この場合は等式)演算子は通常、である必要があることに注意してくださいconst

編集:あなたは左側の引数の静的なタイプに基づいた比較だけを気にするかもしれないようです、それはより簡単な問題であるはずです。この場合、左側の引数が暗黙的にまたは継承以外のメカニズム(変換演算子または変換コンストラクター)によって変換される型である場合を除いて、コードはすべての場合を処理しBaseますDerived。これらのケースを気にしないのであれば、メンバーの平等は問題ありません。

最後に、比較が完全にパブリックインターフェイスを介して実行できる場合、演算子であるかどうかに関係なく、(ほとんど)非メンバー、非フレンド関数を常に優先します。

EDIT2(非会員、非友人の非常に簡単な概要):

たとえば、クラスにpublickeyメソッドがあり、2つのインスタンスのキーが等しい場合は、オブジェクトをequalと呼びます。次に、友達やメンバーの等式演算子を使用せずに、スタンドアロンで等式を記述できます。

bool operator==(const MyType& left, const MyType& right)
{
    return left.key() == right.key();
}
于 2012-07-24T14:34:30.060 に答える
7

メンバー関数自体に問題はありませんが、フリー関数の方が一般的です。メンバー関数は、左側のオペランドを型または子型にする必要がありますが、free関数は、継承ツリーの一部である型だけでなく、BaseClass暗黙的に変換可能なすべての型を受け入れます。BaseClass

于 2012-07-24T14:31:39.903 に答える
4

私が目にする最大の問題virtual bool operator==( BaseClass const &right )は、複数の動的ディスパッチ*がないと、次のアサーションが失敗することです。

class Derived1 : public BaseClass {
    bool operator==( BaseClass const &right ) override {
        return true;
    }
}

class Derived2 : public BaseClass {
    bool operator==( BaseClass const &right ) override {
        return false;
    }
}

Derived1 d1;
Derived2 d2;
assert((d1 == d2) == (d2 == d1));

フレンド機能でこれを処理することもできますが、正直なところ、多重ディスパッチなしでこのようなものを正しく取得するのは大変な作業です。多重ディスパッチを使用しても、このようなポリモーフィック等式演算子の適切なセマンティクスを思い付くのは簡単ではない場合があります。


*複数の動的ディスパッチは、だけでなく、複数の引数に対して動的ディスパッチを実行する機能ですthis

于 2012-07-24T14:36:35.653 に答える
2

あなたが作ろうとしている2つの独立したポイントがあります。まず、スタンドアロン関数ではなく、メンバー関数として演算子を実装します。次に、仮想関数として実装します(タイトルに入力することもできます)。

「仮想」の部分で何を言おうとしているのかは明確ではありません。コードサンプルでは、​​派生クラス演算子は基本クラス演算子をオーバーライドしません。これは、それらのシグネチャが一致しないためです。あなたの例にはポリモーフィズムはありません。だから、それが「うまくいく」と言うことの意味がわかりません。コードにはまだ「機能」できるものがないため、(「仮想」演算子として)実際には機能しません。現時点では、コードはコンパイルするだけですが、何もしません。ポリモーフィックな動作を実証しようとするコードを提供します。そうすれば、それが「機能している」かどうかを確認できます。

二項演算子をメンバー関数として実装することに関して...この問題はすでに何度も取り上げられています。メンバー関数として実装された二項演算子は、暗黙の引数変換に関して「非対称に」動作します。そのため、通常、対称二項演算子をスタンドアロン関数として実装することをお勧めします。

于 2012-07-24T14:39:38.967 に答える