抱歉我的英语不好,我不是母语人士,请使用翻译来回答以下问题。
Context:我有一个任务来实现Scene类和Component类。 Component类是其他组件(ModComponent、EditComponent)的基类,并且有一个虚函数update()。 Scene 类存储 std::list 并具有从列表中添加/获取组件的方法。
获取组件的语法应该是这样的:
scene_object.getComponent<TypeComponent>();
在网上查了很久,我是这样做的:
#include <iostream>
#include <list>
#include <typeinfo>
#include <memory>
class Component
{
public:
virtual void update()
{
std::cout << "BASE COMP" << std::endl;
}
};
class ModComponent : public Component
{
public:
void update()
{
std::cout << "MOD COMP" << std::endl;
}
};
class EditComponent : public Component
{
public:
void update()
{
std::cout << "EDIT COMP" << std::endl;
}
};
class Scene
{
public:
template<class T>
T getComponent()
{
for(auto& ptr : m_comps)
{
std::cout << typeid(*ptr).name() << std::endl;
std::cout << typeid(T).name() << std::endl;
if(typeid(*ptr) == typeid(T))
{
std::cout << "SAME TYPE" << std::endl;
//return *ptr;
}
}
}
template<class T>
void addComponent(T obj)
{
m_comps.push_back(&obj);
}
private:
std::list<Component*> m_comps;
};
int main()
{
Component a;
ModComponent b;
EditComponent c;
a.update();
b.update();
c.update();
Scene sc;
sc.addComponent(a);
sc.addComponent(b);
sc.addComponent(c);
sc.getComponent<Component>.update();
sc.getComponent<ModComponent>();
sc.getComponent<EditComponent>().update();
return 0;
}
理论上应该可行,因为以下几行:
for(auto& ptr : m_comps)
{
std::cout << typeid(*ptr).name() << std::endl;
std::cout << typeid(T).name() << std::endl;
if(typeid(*ptr) == typeid(T))
{
std::cout << "SAME TYPE" << std::endl;
//return *ptr;
}
}
告诉我类型是相等的,但是一旦我取消注释返回,就会立即发生错误:
<source>: In instantiation of 'T Scene::getComponent() [with T = ModComponent]':
<source>:82:24: required from here
<source>:50:29: error: could not convert '* ptr' from 'Component' to 'ModComponent'
50 | return *ptr;
| ^~~
| |
| Component
如有错误欢迎指正。
ptr
方法中的局部变量
getComponent
的类型为
&Component
,因此如果您尝试返回
*ptr
(
Component
类型),编译器会抱怨,因为该方法应该返回
T
(类型为
ModComponent
、
EditComponent
等)。您需要返回声明的返回类型或其子类型的值。如果你确定你返回的确实是
T
类型,那么你可以在投射后返回它:
return *static_cast<ModComponent*>( ptr );
或者(如评论中建议的那样)你可以使用 dynamic_cast
这可能更适合这个:
T* casted = dynamic_cast<T*>(ptr);
if (casted != NULL) {
return *casted;
}
在这两种情况下,我建议您应该返回 T*
而不是
T
,并将其作为
T*
传递给
addComponent
方法。显然,这也需要对方法的行为进行额外的更改。在第一种情况下,取消引用对象的成本可能很高(因为进行了复制),并且对对象的任何更新都不会反映到存储在
Scene
中的对象。在
addComponent
中,您将指针指向局部变量(参数),因此存储此类指针并稍后使用它可能会导致未定义的行为。