为什么编译器告诉我类型是相等的,但不能将它们相互转换? C++

问题描述 投票:0回答:1

抱歉我的英语不好,我不是母语人士,请使用翻译来回答以下问题。

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

如有错误欢迎指正。

c++ oop gcc stl
1个回答
0
投票

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
 中,您将指针指向局部变量(参数),因此存储此类指针并稍后使用它可能会导致未定义的行为。

© www.soinside.com 2019 - 2024. All rights reserved.