std::atomic_ref<T>与子类U的std::atomic_ref<U>之间能否向下转型
问题结论
你无法直接在std::atomic_ref<Base>和std::atomic_ref<Derived>之间做向下转型,即使Derived是Base的公开子类。
核心原因
- C++的模板类型不存在基于模板参数继承关系的默认转换规则,
std::atomic_ref<Component>和std::atomic_ref<Position>是两个完全独立的类型,编译器不支持二者之间的直接转换,这也是你遇到error C2440报错的直接原因。 std::atomic_ref的类型严格绑定到它所指向的实际对象类型,强行对std::atomic_ref做指针转型会违反C++严格别名规则,触发未定义行为,即使你确定底层对象是派生类实例也不允许直接转换atomic_ref本身。
可行解决方案
你可以通过先取出底层对象指针、转型后再构造新的派生类std::atomic_ref的方式实现需求,两种常用实现方案如下:
方案1:修改map存储类型为基类指针(更推荐)
修改你的components map的存储值为Component*类型,取出后先做派生类转型,再构造对应std::atomic_ref返回,示例代码如下:
// 先修改components的定义: // std::unordered_map<componentInstanceId, Component*> components; template<typename T> std::atomic_ref<T> World::getComponentByID(componentInstanceId uuid) const { static componentTypeId key = stringHash(typeid(T).name()); Component* base_ptr = components.at(uuid); // 确认类型匹配时可使用static_cast,需要运行时类型校验则替换为dynamic_cast T* derived_ptr = static_cast<T*>(base_ptr); return std::atomic_ref<T>(*derived_ptr); }
注意:你需要保证指向的派生类对象满足std::atomic_ref要求的对齐规则,且对象生命周期长于所有引用它的std::atomic_ref实例。
方案2:基于现有map存储的基类atomic_ref构造
如果不需要修改map的定义,可以先调用data()方法拿到底层基类指针,转型后再构造派生类的std::atomic_ref:
template<typename T> std::atomic_ref<T> World::getComponentByID(componentInstanceId uuid) const { static componentTypeId key = stringHash(typeid(T).name()); std::atomic_ref<Component> base_ref = components.at(uuid); T* derived_ptr = static_cast<T*>(base_ref.data()); return std::atomic_ref<T>(*derived_ptr); }
注意:必须保证base_ref指向的实际对象就是T类型的实例,否则会触发未定义行为。
内容的提问来源于stack exchange,提问作者RazeLighter777
相关产品推荐
相关产品推荐

