C++ C++;基于子类型动态强制转换结构

C++ C++;基于子类型动态强制转换结构,c++,struct,casting,C++,Struct,Casting,因此,我目前正在尝试创建自己的enitity组件体系结构,我遇到了一些问题 我将组件存储为结构,例如 struct BaseComponent { bool isValid; } struct ComponentA : BaseComponent { int someValForA; } struct ComponentB : BaseComponent { int someValForB } ComponentB* compB = new ComponentB() compB

因此,我目前正在尝试创建自己的enitity组件体系结构,我遇到了一些问题

我将组件存储为结构,例如

struct BaseComponent
{
  bool isValid;
}

struct ComponentA : BaseComponent
{
  int someValForA;
}

struct ComponentB : BaseComponent
{
  int someValForB
}

ComponentB* compB = new ComponentB()
compB->someValForB = 10;
BaseComponent* baseComp = compB

ComponentB* comp = (ComponentB*) baseComp
我希望我的系统能够存储可变继承的结构。所以我需要使用指针向量。问题是,我如何在不知道它们的原始子类型的情况下动态地将它们转换回原始的派生结构?我可以通过没有枚举的代码来确定它们的派生类型,因为我想在库中实现它

我还将回答这个问题,并给出实现这个系统的替代方法,记住我想开发它。如果可能的话,请特别说明并给出代码示例

感谢您阅读:)


这是我今天上传的另一个问题的转载。这是一个重复的问题,但重复的问题甚至没有接近回答我的问题。我请求你通过评论与我交谈,而不是阻止任何人帮助我,从而理解我问题的正确性。谢谢。

如果您的基类是多态的,您可以使用转换回原始类(有点像Java中的
instanceof
):

假设您有以下课程:

struct Base {
    // We need this or any other virtual member to make Base polymorphic
    virtual ~Base () { }
};

struct Derived1: public Base {
    void foo () {
        std::cout << "foo" << std::endl;
    }
};

struct Derived2: public Base {
    void bar () {
        std::cout << "bar" << std::endl;
    }
};
然后,您可以使用以下命令返回到派生类:

for(自动pbase:base){
if(Derived1*d=动态_-cast(pbase)){
d->foo();
}
if(Derived2*d=动态_-cast(pbase)){
d->bar();
}
}
如果强制转换失败,将返回一个空指针,因此如果
pbase
最初是
Derived2*
,那么您将永远不会调用
d->foo()

请注意,如果
Base
不是多态的(请尝试删除
virtual
),则无法使用(编译器错误)


1请注意,您可以(应该)使用智能指针,而不是使用原始指针
Base*
,以避免手动释放内存(例如)。如果这样做,则必须使用而不是
dynamic\u cast

如果基类是多态的,则可以使用转换回原始类(有点像Java中的
instanceof
):

假设您有以下课程:

struct Base {
    // We need this or any other virtual member to make Base polymorphic
    virtual ~Base () { }
};

struct Derived1: public Base {
    void foo () {
        std::cout << "foo" << std::endl;
    }
};

struct Derived2: public Base {
    void bar () {
        std::cout << "bar" << std::endl;
    }
};
然后,您可以使用以下命令返回到派生类:

for(自动pbase:base){
if(Derived1*d=动态_-cast(pbase)){
d->foo();
}
if(Derived2*d=动态_-cast(pbase)){
d->bar();
}
}
如果强制转换失败,将返回一个空指针,因此如果
pbase
最初是
Derived2*
,那么您将永远不会调用
d->foo()

请注意,如果
Base
不是多态的(请尝试删除
virtual
),则无法使用(编译器错误)


1请注意,您可以(应该)使用智能指针,而不是使用原始指针
Base*
,以避免手动释放内存(例如)。如果您这样做,您将不得不使用而不是
dynamic\u cast

或者您可以这样做。它不像霍尔特的回答那样专业,但也有同样的缺点。稍后会有更多关于他们的信息

#include <iostream>
#include <memory>

struct Base {
       virtual int what() const = 0;
       virtual ~Base(){}
};

struct Derived1 : Base {
       static constexpr int ME = 1;

       int what() const{
              return ME;
       }
};

struct Derived2 : Base {
       static constexpr int ME = 2;

       int what() const{
              return ME;
       }
};

using pBase = std::unique_ptr<Base>;

void doSomething(pBase &base){
       switch(base->what()){
       case Derived1::ME :
              std::cout << "Derived1" << std::endl;
              break;

       case Derived2::ME :
              std::cout << "Derived2" << std::endl;
              break;

       default:
              std::cout << "huh?" << std::endl;

       }
}

int main(){
       pBase base1{ new Derived1() };
       pBase base2{ new Derived2() };

       doSomething(base1);
       doSomething(base2);

       //no need to call delete
}
在许多OOP语言中,如
Java
C
PHP
,基本
Shape
类称为
接口
。注意它是如何定义方法的,但不包括任何实现细节


这允许派生类在不同的编译单元中实现,而客户机代码不知道它使用的是什么类。

或者,您也可以这样做。它不像霍尔特的回答那样专业,但也有同样的缺点。稍后会有更多关于他们的信息

#include <iostream>
#include <memory>

struct Base {
       virtual int what() const = 0;
       virtual ~Base(){}
};

struct Derived1 : Base {
       static constexpr int ME = 1;

       int what() const{
              return ME;
       }
};

struct Derived2 : Base {
       static constexpr int ME = 2;

       int what() const{
              return ME;
       }
};

using pBase = std::unique_ptr<Base>;

void doSomething(pBase &base){
       switch(base->what()){
       case Derived1::ME :
              std::cout << "Derived1" << std::endl;
              break;

       case Derived2::ME :
              std::cout << "Derived2" << std::endl;
              break;

       default:
              std::cout << "huh?" << std::endl;

       }
}

int main(){
       pBase base1{ new Derived1() };
       pBase base2{ new Derived2() };

       doSomething(base1);
       doSomething(base2);

       //no need to call delete
}
在许多OOP语言中,如
Java
C
PHP
,基本
Shape
类称为
接口
。注意它是如何定义方法的,但不包括任何实现细节


这允许派生类在不同的编译单元中实现,而客户机代码不知道它使用的是什么类。

您可以通过RTTI获得有关变量类型的信息,如:

 (typeid(*baseComp) == typeid(ComponentB))

这在您的示例中是正确的。

您可以通过RTTI获得有关变量类型的信息,如:

 (typeid(*baseComp) == typeid(ComponentB))

这在您的示例中是正确的。

与其抛出类型信息,然后检查每个组件是否都是您正在关注的组件,我建议您使用一个容器,将类型映射到其组件(或者告诉您它没有)

组件的基类

struct Entity {

    template <class T, class... Args>
    void addComponent(Args &&... args) {
        if(!comps.emplace(
            idFor<T>, std::make_unique<T>(std::forward<Args>(args)...)
        ).second)
            throw std::runtime_error("Component already present.");
    }

    template <class T>
    T *getComponent() {
        auto found = comps.find(idFor<T>);
        return found == end(comps)
            ? nullptr
            : static_cast<T*>(found->second.get());
    }

    std::map<TypeId, std::unique_ptr<Component>> comps;
};
struct实体{
样板
void addComponent(Args&&…Args){
如果(!comps.emplace(

idFor,std::make_unique(std::forward

与其抛出类型信息,然后检查每个组件是否都是您正在关注的组件,我建议您使用一个容器将类型映射到其组件(或者告诉您它没有)

组件的基类

struct Entity {

    template <class T, class... Args>
    void addComponent(Args &&... args) {
        if(!comps.emplace(
            idFor<T>, std::make_unique<T>(std::forward<Args>(args)...)
        ).second)
            throw std::runtime_error("Component already present.");
    }

    template <class T>
    T *getComponent() {
        auto found = comps.find(idFor<T>);
        return found == end(comps)
            ? nullptr
            : static_cast<T*>(found->second.get());
    }

    std::map<TypeId, std::unique_ptr<Component>> comps;
};
struct实体{
样板
void addComponent(Args&&…Args){
如果(!comps.emplace(

idFor,std::make_unique(std::forward

嗨,我几乎没有时间遇到同样的问题。但正如你所说,我总是在BaseComponent中添加并枚举“type”,并在构造子类(或子结构)时将其初始化为其特定类型…动态获取类型是不可能的啊,这是我的备份计划,但如果有其他方法,那么我想知道,但非常感谢您的评论:)在java中,我可以检查父类是否是派生类的实例。如果基类是多态的,则可以使用。如果需要区别对待,为什么要将这些对象存储在一起?嗨,我几乎没有遇到过同样的问题。但正如你所说,我总是添加并枚举“type”在构建子类(或子结构)时将其初始化为其特定类型
struct Entity {

    template <class T, class... Args>
    void addComponent(Args &&... args) {
        if(!comps.emplace(
            idFor<T>, std::make_unique<T>(std::forward<Args>(args)...)
        ).second)
            throw std::runtime_error("Component already present.");
    }

    template <class T>
    T *getComponent() {
        auto found = comps.find(idFor<T>);
        return found == end(comps)
            ? nullptr
            : static_cast<T*>(found->second.get());
    }

    std::map<TypeId, std::unique_ptr<Component>> comps;
};
struct CompA : Component { int attribA; };
struct CompB : Component { int attribB; };
struct CompC : Component { int attribC; };

int main() {
    Entity e;
    e.addComponent<CompA>();
    e.addComponent<CompB>();

    if(CompA *c = e.getComponent<CompA>()) {
        std::cout << "Retrieved component A\n";
        c->attribA = 42;
    }

    if(CompB *c = e.getComponent<CompB>()) {
        std::cout << "Retrieved component B\n";
        c->attribB = 42;
    }

    if(CompC *c = e.getComponent<CompC>()) {
        std::cout << "Retrieved component C\n";
        c->attribC = 42;
    } else {
        std::cout << "Didn't retrieve component C\n";
    }
}
Retrieved component A Retrieved component B Didn't retrieve component C