派生クラスとを含む抽象基本クラス があると想像してください。Shape
Circle
Rectangle
class Shape {};
class Circle : public Shape {};
class Rectangle : public Shape {};
Shape*
2つのポインターがあると仮定して、2つの形状が等しいかどうかを判断する必要があります。(これは、のインスタンスが2つありvector<Shape*>
、それらが同じ形状であるかどうかを確認したいためです。)
これを行うための推奨される方法は、ダブルディスパッチです。私が思いついたのはこれです(ここでは非常に単純化されているため、形状は同じタイプの他のすべての形状と同じです):
class Shape {
public:
virtual bool equals(Shape* other_shape) = 0;
protected:
virtual bool is_equal(Circle& circle) { return false; };
virtual bool is_equal(Rectangle& rect) { return false; };
friend class Circle; // so Rectangle::equals can access Circle::is_equal
friend class Rectangle; // and vice versa
};
class Circle : public Shape {
public:
virtual bool equals(Shape* other_shape) { return other_shape->is_equal(*this); };
protected:
virtual bool is_equal(Circle& circle) { return true; };
};
class Rectangle : public Shape {
public:
virtual bool equals(Shape* other_shape) { return other_shape->is_equal(*this); };
protected:
virtual bool is_equal(Rectangle& circle) { return true; };
};
これは機能しますが、派生クラスごとに個別のequals
関数とfriend
宣言を追加する必要があります。次に、まったく同じ関数を各派生クラスにShape
コピーして貼り付ける必要があります。これは、たとえば10種類の形状の場合、非常に多くの定型文です。equals
それを行うためのより簡単な方法はありますか?
dynamic_cast
問題外です。遅すぎる。(はい、ベンチマークしました。アプリでは速度が重要です。)
私はこれを試しましたが、機能しません:
class Shape {
public:
virtual bool equals(Shape* other_shape) = 0;
private:
virtual bool is_equal(Shape& circle) { return false; };
};
class Circle : public Shape {
public:
virtual bool equals(Shape* other_shape) { return other_shape->is_equal(*this); };
private:
virtual bool is_equal(Circle& circle) { return true; };
};
class Rectangle : public Shape {
public:
virtual bool equals(Shape* other_shape) { return other_shape->is_equal(*this); };
private:
virtual bool is_equal(Rectangle& circle) { return true; };
};
equals()
同じ形状であっても、常にfalseを返します。is_equal(Shape&)
「より具体的な」一致が利用可能な場合でも、ディスパッチは常に基本機能を選択しているようです。これはおそらく理にかなっていますが、理由を理解するのに十分なほどC++ディスパッチを理解していません。