什么类型的演员适合这里?

时间:2015-09-09 10:10:37

标签: c++ oop templates

我有一个名为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永远不会失败。

2 个答案:

答案 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没有。