我有两个类,一个用于存储基础数据,另一个用于存储其他数据,如下所示:
struct AnimationState(){
virtual ~ AnimationState(){};
Vector3f m_spacialData;
float m_fTimeStamp;
}
派生类:
struct HermiteAnimationState() : public AnimationState{
virtual ~HermiteAnimationState(){};
Vector3f m_tangentIn;
Vector3f m_tangentOut;
}
我的问题:我是如何创建 HermiteAnimationState 的实例,然后将其向上转换为 AnimationState 进行存储的像这样的矢量:
std::vector<AnimationState> m_vStates;
...
最近,我可以获取对象 AnimationState 并将其向下转换为 HermiteAnimationState 以访问其他数据(成员m_tangentIn和m_tangentOut)。
HermiteAnimationState* p = dynamic_cast<HermiteAnimationState*>(&m_vStates[i])
答案 0 :(得分:1)
多态在C ++中的工作方式是,如果B
是基类而D
是从B
派生的,那么:
D
的指针可用于指向B
的指针D
的引用可用于预计会引用B
您在C ++中无法做的事情实际上是在值的上下文中使用类型为D
的值类型B
是预期的。例如,您不能将派生对象存储在基础对象的数组中。当您考虑派生对象可能与基础对象具有不同的大小时,这是有意义的。
同样,您不能将派生对象存储在基础对象的矢量中。
可以做的是将指针存储在指针到HermiteAnimationState
的向量中的AnimationState
。这取决于你如何管理内存。例如,以下内容有效:
std::vector<AnimationState*> m_vStates;
HermiteAnimationState h_a_s;
m_vStates.push_back(&h_a_s);
...
HermiteAnimationState* p = dynamic_cast<HermiteAnimationState*>(m_vStates[i])
由于h_a_s
是一个局部变量,它将在其范围的末尾自动销毁。
但这可能是 一种不可行的方法,因为你可能希望vector元素引用的对象持久存在于当前范围之外。我们可以将std::unique_ptr
用于此目的。 std::unique_ptr
拥有它指向的对象,只要它保持活着,该对象也是如此;它会在它自身被销毁时删除它。因此,std::unique_ptr
对象的向量在内存管理方面就像对象本身的向量。现在你可以做到
std::vector<std::unique_ptr<AnimationState*>> m_vStates;
m_vStates.emplace_back(new HermiteAnimationState);
...
HermiteAnimationState* p =
dynamic_cast<HermiteAnimationState*>(m_vStates[i].get());
(但请注意,您无法复制此向量;您只能移动它。)
答案 1 :(得分:1)
基本上,您需要对指向对象使用某种引用,因为您需要动态多态。
最简单但容易出错的是使用“裸”指针。对此有问题的第一件事是你必须手动破坏:容器会破坏指针,而不是指向的东西。
更安全的方法是使用智能指针,这些指针旨在根据智能指针嵌入其类型的预先固定的规则进行销毁。最简单的一个,当然是最好的选择,如果你怀疑是std :: unique_ptr,它不能复制但可以移动。另一个选择,在使用之前应该仔细考虑,是std :: shared_ptr,它是有用的IFF,你不知道什么时候你应该销毁这些对象,但是你知道当某些系统不再引用它时。其他一些系统可能只是在观察那个对象,在这种情况下是std :: weak_ptr。
现在,通过阅读您的问题,我认为您肯定正在处理大量这些动画数据。那里有一个明显的设计问题,我想,我可能错了。 但是,看起来,如果要管理很多这些AnimationState,在循环中,您将遇到性能问题。这是游戏中的常见问题,主要是由“缓存一致性”引起的。
在这种情况下,我建议不要使用
然而,我的建议更为激烈:根本不使用继承。
显然,这只是一个建议。如果你没有做一个关键循环的事情,那没关系。我只是担心,因为看起来你正在为组合做一些继承,这对代码的可读性和性能都会产生不良影响。