我有一个名为BaseNode
的抽象类模板,如此定义
template<class T>
class BaseNode
{
public:
T* addChildNode(const char *name);
void deleteChildNode(const char *name);
void deleteAllChildNodes();
T* findFirstNode(const char *name);
T* getChildNode(const char *name);
T* getChildNode(unsigned int index);
void setName(const char *name);
void setTranformation(const glm::mat4 &transformation);
unsigned int getNumChildren() const { return _children.size(); }
const char *name() const { return _name.c_str(); }
T* parent() const { return _parent; }
const glm::mat4& transformation() const { return _transformation; }
const glm::mat4& toRootTransformation() const { return _toRoot; }
protected:
BaseNode(const char *nodeName, T *parent);
virtual ~BaseNode();
std::string _name;
glm::mat4 _transformation;
glm::mat4 _toRoot;
T *_parent;
std::vector<T*> _children;
};
这个类的功能是我可以创建自己的“节点类”类型,然后它们将继承此类模板的所有场景图方法。 (例如class MyNode : public BaseNode<MyNode> {...};
当addChildNode(const char *name)
应该是孩子的父母时,new T(name, this)
函数会向子矢量插入this
。编译器抛出一个转换错误,并建议我使用某种类型的转换。我现在正在使用dynamic_cast
,但这真让我烦恼,因为我觉得它没用。
我的问题是,在这种情况下使用reinterpret_cast(基本上就像C-cast ......?)是安全的,如下所示:_children.push_back(new T(name, reinterpret_cast<T*>(this)));
因为IMO dynamic_cast永远不会失败。
答案 0 :(得分:2)
这是Curiously recurring template pattern的示例,因此static_cast
在这里是惯用的。
在这种情况下,您可以通过多种方式避免施放。最简单的是将构造函数更改为:
BaseNode(const char* nodeName, T* parent, T* thisAsT);
并添加适当的字段:
//...
T* _parent;
T* _thisAsT;
因此,在addChildNode
中,您可以轻松访问具有相应类型的this
指针:
_children.push_back(new T(name, _thisAsT));
这当然要求派生类在其构造函数中为此参数提供有效的指针。
另一个,但有点kludgey是添加:
virtual T* buildFromName(const char* name) = 0;
然后在addChildNode
中使用它:
_children.push_back(buildFromName(name));
但是,这需要派生类为自己的类型实现工厂方法,例如违反SRP。另一方面,为每个派生类创建工厂类型似乎有点过头了。
第二个想法,具有与上述类似的属性:
virtual T* getThis() = 0;
然后:
_children.push_back(new T(name, getThis()));
很少注意事项:
- 考虑使用std::string
代替const char*
- 声明应该写成T* x
而不是T *x
(也是const char* x
而不是const char *x
) - 明星不是变量名称的一部分,它是类型说明符的一部分,因此应该在“类型侧”
答案 1 :(得分:1)
static_cast是正确的。
dynamic_cast比你需要的要慢得多。
reinterpret_cast不正确。您不知道派生对象的基类部分与派生对象在同一位置开始。如果需要,静态转换会调整地址。 reinterpret_cast没有。