ビジターパターンコードのダウンキャストを避けるために、誰でも前後にサンプルコードを表示できますか?
ありがとう。
素朴でミニマルな例。
class Base {};
class Derived1 : public Base {};
class Derived2 : public Base {};
// Some arbitrary function that handles Base.
void
Handle(Base& obj) {
if (...type is Derived1...) {
Derived1& d1 = static_cast<Derived1&>(base);
std::printf("Handling Derived1\n");
}
else if (...type is Derived2...) {
Derived2& d2 = static_cast<Derived2&>(base);
std::printf("Handling Derived2\n");
}
}
つまりBase
、タイプタグフィールドが必要です。そうでない場合はdynamic_cast
、各タイプをチェックするために使用します。
// Class definitions
class Visitor;
class Base {
public:
// This is for dispatching on Base's concrete type.
virtual void Accept(Visitor& v) = 0;
};
class Derived1 : public Base {
public:
// Any derived class that wants to participate in double dispatch
// with visitor needs to override this function.
virtual void Accept(Visitor& v);
};
class Derived2 : public Base {
public:
virtual void Accept(Visitor& v);
};
class Visitor {
public:
// These are for dispatching on visitor's type.
virtual void Visit(Derived1& d1) = 0;
virtual void Visit(Derived2& d2) = 0;
};
// Implementation.
void
Derived1::Accept(Visitor& v) {
v.Visit(*this); // Calls Derived1 overload on visitor
}
void
Derived2::Accept(Visitor& v) {
v.Visit(*this); // Calls Derived2 overload on visitor
}
それがフレームワークでした。ここで、実際の訪問者を実装して、オブジェクトを多態的に処理します。
// Implementing custom visitor
class Printer : public Visitor {
virtual void Visit(Derived1& d1) { std::printf("Handling Derived1\n"); }
virtual void Visit(Derived2& d2) { std::printf("Handling Derived2\n"); }
};
// Some arbitrary function that handles Base.
void
Handle(Base& obj)
{
Printer p;
obj.Accept(p);
}
Accept()
obj
(最初のディスパッチ)のタイプでディスパッチする仮想関数ですVisit()
、内部Accept()
でオブジェクトのタイプがすでにわかっているためです。Visit()
は、訪問者のタイプに応じてディスパッチする仮想関数です(2回目のディスパッチ)。ダブルディスパッチ(1つはオブジェクト、もう1つはビジター)があるため、キャストは行いません。欠点は、階層にクラスを追加するたびに、訪問者クラスに移動して更新し、新しいサブクラスを処理するための適切な関数を追加する必要があることです。
ウィキペディアの例では、ダブル ディスパッチを使用し、ダウンキャストは使用していません。