什么类型的cast在这里是合适的

What type of cast is appropriate here?

本文关键字:cast 类型 什么 在这里      更新时间:2023-10-16

我有一个叫做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> {...};

)

this应该是子向量的父向量时,addChildNode(const char *name)函数将new T(name, this)插入子向量。编译器抛出一个类型转换错误,并建议我为此使用某种类型转换。我使用dynamic_cast的时刻,但这真的困扰我,因为我认为它是无用的。

我的问题是,在这种情况下,使用reinterpret_cast(基本上就像C-cast ..?)是否安全:_children.push_back(new T(name, reinterpret_cast<T*>(this)));因为IMO dynamic_cast永远不会失败

这是一个奇怪的重复出现的模板模式的例子,所以static_cast在这里是惯用的。

在这种情况下,可以通过多种方法避免强制转换。最简单的方法是将构造函数修改为:

BaseNode(const char* nodeName, T* parent, T* thisAsT);

并添加适当的字段:

//...
T* _parent;
T* _thisAsT;

因此在addChildNode中,您可以轻松访问this指针,并使用适当的类型:

_children.push_back(new T(name, _thisAsT));

这当然要求派生类在其构造函数中为该实参提供一个有效的指针。


另一个,不过有点笨拙的是添加:

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) -星号不是变量名的一部分,它是类型说明符的一部分,所以应该在"类型侧"

一个static_cast是正确的
Dynamic_cast比您需要的慢得多。Reinterpret_cast不正确。您不知道派生对象的基类部分是否在与派生对象相同的位置开始。如果需要,静态强制转换会调整地址。reinterpret_cast则没有。

dynamic_cast和reinterpret_cast仍然不同。如果基类和派生类的大小不同,则指向同一对象的基类指针和派生类指针可能有不同的地址——如果存在虚表的话。

参见:关于基类和派生类对象的动态类型转换和地址

如果没有虚方法,则使用static_cast进行编译时强制转换(执行速度更快)。