3

クラスでa を定義しvirtual operator==ました。Baseしかし、どういうわけか、実際には仮想として扱われていないようです。

次のコード例を参照してください。

#include <iostream>
#include <boost/unordered_set.hpp>

template<class T> struct EqualByValue {
  bool operator()(T const* a, T const* b) const { return *a == *b; }
};

struct Base {
  virtual bool operator==(Base const& other) const {
    std::cerr << "Base==" << std::endl;
  }
};

struct Derived : Base {
  virtual bool operator==(Derived const& other) const {
    std::cerr << "Derived==" << std::endl;
  }
};

int main(int argc, char** argv){
  typedef boost::unordered_set<Base*, boost::hash<Base*>, EqualByValue<Base> > 
    MySet;
  MySet s;
  Derived* d1 = new Derived();
  Derived* d2 = new Derived();
  s.insert(d1);
  s.insert(d2);
  s.find(d2);
  delete d1; delete d2; return 0;
}

出力はBase==、目的の出力ではありませんDerived==

それはなぜですか、どうすれば修正できますか?

4

2 に答える 2

2

( 2 つのオブジェクトの動的な型が異なる場合、等価性は false であるという単純な仮定を行う、より単純なソリューションを最後に追加しました。 )

内部の派生は、内部のベースoperator==をオーバーライドしません。operator==には異なる署名があり、1 つは Base& を as として受け入れ、もう 1 つはotherDerived& を受け入れます。オーバーライドが機能するには、それらが同一である必要があります (戻り値の型を少し変更できますが、パラメーターの型は変更できません)。

解決策の 1 つは、二重ディスパッチでこれを修正することです。real_comparator実際に比較作業を行うメソッド (またはおそらくフリー関数) を定義しました。real_comparatorには、Base クラスと Derived クラスのそれぞれに 2 つずつ、合計 4 つのバージョンがあります。

を行うときはa==b、両方の変数の動的タイプを考慮に入れる必要があります。a==bはコンパイラによって として書き換えられるa.operator==(b)ため、デフォルトではa、ポリモーフィズムに参加するのは だけです。これを変更して、両方の変数 (したがって、4 つの可能性すべて) をアクティブにできるようにします。

トリックはreturn other.real_comparator(*this);

struct Derived;

struct Base {
  virtual bool real_comparator(Base const& /*other*/) const {
          std::cerr << "Base == Base?" << std::endl;
          return false;
  }
  virtual bool real_comparator(Derived const& /*other*/) const {
          std::cerr << "Base == Derived?" << std::endl;
          return false;
  }

  virtual bool operator==(Base const& other) const {
    return other.real_comparator(*this);
  }
};

struct Derived : Base {
  virtual bool real_comparator(Base const& /*other*/) const override {
          std::cerr << "Derived == Base?" << std::endl;
          return false;
  }
  virtual bool real_comparator(Derived const& /*other*/) const override {
          std::cerr << "Derived == Derived?" << std::endl;
          return false;
  }

  virtual bool operator==(Base const& other) const override {
    return other.real_comparator(*this);
  }
};

このコードは、特に「2 つのオブジェクトの動的タイプが異なる場合、比較の結果は常に false になる」などのルールがある場合は、少し簡略化できると思います。


より簡単な解決策が可能ですが、解決したい問題によって異なります。2 つのオブジェクトの動的な型が異なる場合、比較で false が返されると仮定しましょう。

#include<typeinfo>  // We need this for typeid to work
using namespace std;

struct Base {
  virtual bool operator==(Base const& other) const {
          if(typeid(other) != typeid(*this))
                  return false;
          else  
                cout << "A pair of Bases" << endl;
          return true; // replace this with code to compare two Base objects
  }
};

struct Derived : Base {

  virtual bool operator==(Base const& other) const override {
          if(typeid(other) != typeid(*this))
                  return false;
          else  
                cout << "A pair of Deriveds" << endl;

          // So 'other' is actually a Derived.
          const Derived * derived_pointer = dynamic_cast<const Derived*>(&other);
          // Now, we can compare 'this' to 'derived_pointer', both pointers to Derived
          return derived_pointer == this; // replace this with code to compare two Derived
  }
};

これは正しいはずですが、何らかの方法で改善できる可能性があります。フィードバックをいただければ幸いです。

于 2013-11-13T11:19:58.370 に答える