C++ 将派生类型转换为基类型

C++ 将派生类型转换为基类型,c++,casting,C++,Casting,我试图学习从基类到派生类的类型转换。这个示例将向您展示我正在尝试做的事情。我知道这不是一个有效的解决方案。我只是想为我的软件创建一个动态的体系结构,并公开征求建议和解决方案 enum EComponentType { Base = 0, Material = 1 }; class FComponent { public: FComponent() { m_type = EComponentType::Base; } EComponentType type()

我试图学习从基类到派生类的类型转换。这个示例将向您展示我正在尝试做的事情。我知道这不是一个有效的解决方案。我只是想为我的软件创建一个动态的体系结构,并公开征求建议和解决方案

enum EComponentType
{
    Base = 0,
    Material = 1
};

class FComponent
{
public:
    FComponent() { m_type = EComponentType::Base; }

    EComponentType type() { return m_type; }

protected:
    EComponentType m_type;

};

class FMaterial : public FComponent
{
public:
    FMaterial() { m_type = EComponentType::Material; }

    void setValue(int value) { m_value = value; }
    int value() { return m_value; }

private:
    int m_value;

};

int main(int argc, char *argv[])
{
    FMaterial material;
    material.setValue(22);

    QVector<FComponent> Components;
    Components << material;

    for (int i = 0; i < Components.size(); i++)
    {
        switch (Components[i].type())
        {
        case EComponentType::Material:

            FMaterial material = (FMaterial)(Components[i]); // --> invalid of course

            int value = material.value();
            break;
        }
    }

    return 0;
}
enum生态组件类型
{
基数=0,
材料=1
};
类别F组件
{
公众:
FComponent(){m_type=ecoComponentType::Base;}
EComponentType(){return m_type;}
受保护的:
生态型m_型;
};
类别F材料:公共F组件
{
公众:
FMaterial(){m_type=ecocomponenttype::Material;}
void setValue(int value){m_value=value;}
int value(){return m_value;}
私人:
int m_值;
};
int main(int argc,char*argv[])
{
材料;
材料。设定值(22);
矢量分量;
组件当然无效
int value=material.value();
打破
}
}
返回0;
}
更新1:

int main(int argc, char *argv[])
{
    QVector<FComponent*> Components;

    FMaterial material;
    material.setValue(22);


    Components << &material;

    for (int i = 0; i < Components.size(); i++)
    {
        switch (Components[i]->type())
        {
        case EComponentType::Material:

            FMaterial *m = static_cast<FMaterial*>(Components[i]);

            int value = m->getValue();
            qDebug() << value;
            break;
        }
    }

    return 0;
}
intmain(intargc,char*argv[])
{
矢量分量;
材料;
材料。设定值(22);
组件类型())
{
案例EComponentType::材质:
FMaterial*m=静态铸件(部件[i]);
int value=m->getValue();

qDebug()虽然我不同意您的总体设计,但这里是如何修复您的解决方案:

使用
static_-cast
而不是
dynamic_-cast
,它会工作。
dynamic_-cast
也会工作,如果您将至少一个虚拟函数放入基类,但它是一个多余的功能,并且与类型枚举一起是多余的

编辑:我刚才还注意到,您尝试强制转换值,在类的情况下,您必须对类指针或引用进行强制转换

class FComponent
{
public:
    // Withtout this if you delete an FComponent* then the destructor of the derived class isn't called.
    virtual ~FComponent() {}
};

class FMaterial : public FComponent
{

};

int test()
{
    QVector<FComponent*> Components;
    FMaterial* material = new FMaterial;
    Components << material;

    for (int i = 0; i < Components.size(); i++)
    {
        switch (Components[i].type())
        {
        case EComponentType::Material:
            FMaterial* material = static_cast<FMaterial*>(Components[i]);
            int value = material->value();
            break;
        }
    }

    // Somewhere later in your code....            
    for (int i = 0; i < Components.size(); i++)
        delete Components[i];
    // TODO: remove all deleted pointers from Components

    return 0;
}
class FComponent
{
公众:
//如果删除FComponent*,则不会调用派生类的析构函数。
虚拟~FComponent(){}
};
类别F材料:公共F组件
{
};
int测试()
{
矢量分量;
F材料*材料=新的F材料;
组件值();
打破
}
}
//在代码后面的某个地方。。。。
对于(int i=0;i
error:C2440:“static_cast”:无法从“FComponent”转换为“FMaterial”没有构造函数可以采用源类型,或者构造函数重载解析不明确您只能转换指针或引用,不是实际的类类型。@cahitburaküçkuksütcü如果是类,则必须对类指针或类引用执行强制转换。您必须将
Base*
强制转换为
Derived*
才能使其工作,如果您尝试按值强制转换,则它不是您想要的强制转换,这将是一种转换,它希望通过转换在您的情况下不起作用的基类来创建新的派生实例。@CahitBurakKüçüksütcü虽然您已经接受了我的解决方案,但我添加了一些示例代码。代码当然不会编译,因为我没有
QVector
,而且我还没有实际编译/测试它,我的
FComponent
/
FMaterial
类只是部分实现。请注意,您需要虚拟析构函数,最后必须
删除容器中的所有项(除非您在其他地方删除这些项),以避免泄漏。@cahitburaküçksütcü让我们说得更清楚一点:首先使用“delete baseclass pointer”语句删除组件对象,然后你仍然有一个向量,其中包含指向内存区域的无效指针,你从中删除了你的对象,并将这些内存区域返回给你的分配器/内存管理器。因此,通过移除容器中的“无效指针”清空容器是一种很好的做法。如果您在容器中按值存储基类实例,那么这将永远不会起作用,因为您无法按值将派生实例放入容器中。在您的案例中,必须在容器中存储基类指针
FComponent*
。在这种情况下,您可以使用
new
创建派生实例,然后可以轻松地将派生实例指针转换为基类指针,并将其放入容器中。另外,如果使用基类指针删除实例,请不要忘记在基类中提供一个虚拟析构函数。您不需要检查任何内容的类型,虚拟函数用于自动处理基类和派生类之间的差异。而将派生对象强制转换为基类是毫无意义的,派生对象是基类的对象。就像你一样,作为参与者,你仍然是一个人。@vonbrand你能解释得更多吗?或者只是做一篇示例文章,例如派生类B有一个成员“intB”,派生类C有一个成员“intC”。如何使用它们。如何准确地读取它们的值'@vonbrand'。只有少数几年发生一次的情况,我使用类似OP模式的黑客作为性能黑客,以避免连续几次虚拟呼叫。。。更不用说,在现实中,大多数桌面应用程序在其代码中的任何地方都远远不是性能关键的,所以优秀的设计具有优先权。