shared_pr 假设 static_pointer_cast 和 dynamic_pointer_cast 做你想做的事。但是,鉴于您有一组固定的节点类型,我强烈推荐访问者模式。鉴于您似乎在做一个场景图,我更倾向于推荐它,因为访问者的最佳用法是使用场景图。
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 知道 'this' 是一个 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);
}
...
};
最初,这种访问者模式很难接近。然而,它在场景图中非常受欢迎,因为它非常擅长处理一小组节点类型,而且它是解决问题的最安全的方法