shared_pr は、あなたが望むことを行う static_pointer_cast と dynamic_pointer_cast を想定していました。ただし、ノード タイプの固定セットがあることを考えると、ビジター パターンを強くお勧めします。シーン グラフを使用しているように見えることを考えると、Visitor の最適な使用法はシーン グラフを使用することであるため、私はそれをお勧めしたいと思います。
class Material;
class Node;
class Color;
class Texture;
class Shape;
class Light;
class Visitor
{
public:
virtual void visit(const shared_ptr<Material>& inNode) = 0;
virtual void visit(const shared_ptr<Color>& inNode) = 0;
virtual void visit(const shared_ptr<Texture>& inNode) = 0;
virtual void visit(const shared_ptr<Shape>& inNode) = 0;
virtual void visit(const shared_ptr<Light>& inLight) = 0;
}
class Node
{
public:
virtual void accept(Visitor& inVisitor) = 0;
};
class Color
: public Node
, public boost::enable_shared_from_this<Color>
{
public:
virtual void accept(Visitor& inVisitor)
{
inVisitor.visit(shared_from_this());
}
...
};
class Texture
: public Node
, public boost::enable_shared_from_this<Texture>
{
public:
virtual void accept(Visitor& inVisitor)
{
inVisitor.visit(shared_from_this());
}
...
};
class Shape
: public Node
, public boost::enable_shared_from_this<Shape>
{
public:
virtual void accept(Visitor& inVisitor)
{
inVisitor.visit(shared_from_this());
}
...
};
class Light
: public Node
, public boost::enable_shared_from_this<Light>
{
public:
virtual void accept(Visitor& inVisitor)
{
inVisitor.visit(shared_from_this());
}
...
};
このパターン全体の目的は、dynamic_cast と同様のことを行うことですが、任意の dynamic_cast の代わりに仮想関数呼び出しのペアを使用して行われるだけです。Node::accept は、オブジェクトの正確なタイプを認識している関数を呼び出す責任があります (つまり、Light::accept は「これ」が Light* であることを認識しています)。次に、「正しい」タイプ情報を使用して訪問者の訪問関数を呼び出します。
このシステムは、少数の型セットで動作する多数のアルゴリズムをサポートするように設計されています。たとえば、 setChild 関数
class SetMaterialChild
: public Visitor
{
public:
SetMaterialChild(Material& inMaterial)
: mMaterial(inMaterial)
{ }
virtual void visit(const shared_ptr<Color>& inNode)
{
mMaterial.mColor = inNode;
}
virtual void visit(const shared_ptr<Texture>& inNode)
{
mMaterial.mTexture = inNode;
}
virtual void visit(const shared_ptr<Shape>& inNode)
{
throw std::runtime_error("Materials cannot have shapes");
}
virtual void visit(const shared_ptr<Light>& inLight)
{
throw std::runtime_error("Materials cannot have lights");
}
private:
Material& mMaterial)
};
class Material
: public Node
, public boost::enable_shared_from_this<Material>
{
public:
virtual void accept(Visitor& inVisitor)
{
inVisitor.visit(shared_from_this());
}
void setNode(const shared_ptr<Node>& inNode)
{
SetMaterialChild v(*this);
inNode->accept(v);
}
...
};
この訪問者パターンは、最初はアプローチするのが困難です。ただし、ノード タイプの小さなセットの処理が非常に優れているため、シーン グラフで非常に人気があり、問題にアプローチする最も型安全な方法です。