1

ここでそれはコードで説明されています:

//Sphere and Box inherit from IShape
//
//Sphere methods:
//bool Sphere::Intersect(Sphere* sphere)
//bool Sphere::Intersect(Box* box);
//
//Box methods:
//bool Box::Intersect(Sphere* sphere)
//bool Box::Intersect(Box* box)

IShape* shapeA;
IShape* shapeB;

shapeA= new Sphere();
shapeB= new Box();

bool areTheyIntersecting = shapeA->Intersect(shapeB); //problem is here?

ポリモーフィズムを使用するそのような方法はこれまでに機能しますか、それともクラスがお互いのタイプを認識して、呼び出す適切なメソッドを知っているようにする別の方法を探す必要がありますか?

4

4 に答える 4

2

あなたが説明している問題は、ダブルディスパッチとして知られています。多くの解決策があります。それらはすべてさまざまな方法で吸います。

彼らが嫌う根本的な理由は、ダブルディスパッチはタイプの数とともに二次的にサイズが大きくなり、二次量のコードを書くことは常に悪いことです。

1つのアプローチは、一般的なダブルディスパッチをいくつかの特殊なケース(球体など)を使用してシングルディスパッチに減らす方法を見つけることです。

タイプの数が限られている場合は、2セットの仮想関数を使用できます。1つ目は、その他を抽象基本クラスとして使用します。他の関数のセットには、可能な引数として各実装クラスがあります。抽象基本クラスは各実装で実装され、これを引数として抽象ベースをとらない「他の関数セット」の最初の引数として他のオブジェクトを呼び出します。

つまり、をcollide(base* other)呼び出しますother->collideSpecific (this)

CRTPは、ボイラープレートの一部を減らすために使用できます。

于 2012-12-22T19:53:54.627 に答える
1

このシナリオでは、ダブルディスパッチと呼ばれるものが必要です。ScottMeyersによるより効果的なC++とAlexendrescuによるModernC++Designをご覧ください。

これもそれについて議論している別の記事です http://www.drdobbs.com/double-dispatch-revisited/184405527

于 2012-12-22T19:50:53.847 に答える
1

これを回避する1つの方法は、各クラスでuint変数を宣言し(またはクラスから抽出可能、以下を参照)、問題のオブジェクトに対してこの変数を返す仮想関数を使用することです。次に、のハッシュを宣言します<std::pair<uint,uint>,std::function<bool(IShape*, IShape*)>>

ハッシュには、特定のオブジェクトタイプの処理方法を知っている関数が含まれ、一般的な呼び出しは次のようになります。

auto key = std::pair<uint,uint>(obj1.typeNumber(), obj2.typenumber())
funchash[key](obj1, obj2);

このマニュアルに示されているように、番号をハードコーディングする必要はありません。http: //shaderop.com/2010/09/uniquely-identifying-types-in-c-without-using-rtti/index.html これは、基本的にその方法を示しています。クラス名をタイプIDにします。

確かに、これはまだ多くの定型文を意味しますが、クラス内にそれを含めるのは好きではありません。このタイプのメカニズムは、とにかくそれ自体がちょっと便利です。

于 2012-12-22T20:16:10.657 に答える
1

ダブルディスパッチは通常、ビジターパターンを介して使用されますが、ビジター自体が要素であるため、少し奇妙です。

一言で言えば、アイデア:

  • 名前付きのIShape/のペアから開始し、これからIShapeleftright
  • 引数として渡すときにintersectメソッドを呼び出します。メソッド内で正確な型( !)を認識し、 onの適切なオーバーロードを呼び出すことでそのことを通知します(leftrightintersectleftSphererightintersectrightSphere
  • intersectの呼び出し内で、rightそのright正確なタイプを知っており私たちも正確なタイプを渡したleftので、今ではそれらすべてを知っています!

簡単な実装:

class IShape {
public:
    virtual ~IShape() {}

    virtual bool intersect(IShape const& other) const = 0;

    virtual bool intersect(Box const& other) const = 0;
    virtual bool intersect(Sphere const& other) const = 0;
}; // class IShape

class Box: public IShape {
public:
    virtual bool intersect(IShape const& other) const override {
        std::cout << "-> Box::intersect(IShape)\n";
        return other.intersect(*this);
    }

    virtual bool intersect(Box const& other) const override {
        std::cout << "-> Box::intersect(Box)\n";
        /* compute intersection of two boxes */
        return false;
    }

    virtual bool intersect(Sphere const& other) const override {
        std::cout << "-> Box::intersect(Sphere)\n";
        /* compute intersection of a box and a sphere */
        return false;
    }
}; // class Box

// Likewise implementation of Sphere

完全な実装により、次の出力が得られます。

int main() {
   Box const box;
   Sphere const sphere;
   IShape const& ibox = box;
   IShape const& isphere = sphere;


   box.intersect(sphere);
   // output
   // -> Box::intersect(Sphere)


   ibox.intersect(sphere);
   // output
   // -> Box::intersect(Sphere)


   sphere.intersect(ibox);
   // output
   // -> Sphere::intersect(IShape)
   // -> Box::intersect(Sphere)


   isphere.intersect(ibox);
   // output
   // -> Sphere::intersect(IShape)
   // -> Box::intersect(Sphere)
}

この戦略は、IShape / IShapeから開始するときに2つの連続するダブルディスパッチがあり、動的タイプを「推定」する必要がある変数ごとに1つのディスパッチがあるため、ダブルディスパッチと呼ばれます。

于 2012-12-22T20:28:54.037 に答える