我可以在循环遍历 vector<shared_ptr> 时以某种方式调用派生类方法<BaseClass>吗?



我有以下问题:

class Component
{
public:
virtual void update(){};
};

class TestComponent : public Component
{
void update()override;
};

class GameObject
{
public :
void addComponent(Component& comp)
{
std::shared_ptr<Component> test = std::make_shared<Component>(comp);
components.push_back(test);
}
void GameObject::update()
{
for(auto comp : components)
{
//I want to call the derived update here without casting it to the derived class if possible
comp->update();
}
}
private:
std::vector<std::shared_ptr<Component>> components;
};
Somewhere else in my code:
GameObject go;
TestComponent comp;
go.addComponent(comp);

我只是假设,当我将一个对象添加到Components的向量中时,我可以简单地对所有向量元素调用update,它使用我传递到addComponent中的对象的重写更新。因此,对于我上面的例子,我希望forloop调用我添加的TestComponent的更新,而不是基类更新。但事实并非如此,所以我想我错过了什么。或者,也许我的方法总体上是错误的。我真的不确定我对共享指针的使用情况?如有任何正确方向的提示,我们将不胜感激。

向量中没有TestComponent对象。它们都是Components。

void addComponent(Component& comp)
{
std::shared_ptr<Component> test = std::make_shared<Component>(comp);
components.push_back(test);
}

在这个函数中,您创建一个新的Component对象,它是您传入的TestComponent对象的Component子对象的副本。这被称为对象切片。

您需要避免复制对象,或者实现某种可克隆的接口。

为了避免复制对象,你可以这样做:

class GameObject
{
public:
void addComponent(std::shared_ptr<Component> comp)
{
components.push_back(comp);
}
// ...
};
int main() {
GameObject go;
std::shared_ptr<TestComponent> testComponent = std::make_shared<TestComponent>();
go.addComponent(testComponent);
}

在这种情况下,maingo共享单个TestComponent对象的所有权。如果你想避免这种情况,你可以实现一个可克隆的接口,这样对象就知道如何复制自己:

class Component
{
public:
virtual void update(){};
virtual std::shared_ptr<Component> clone() const
{
return std::make_shared<Component>(*this);
}
};

class TestComponent : public Component
{
void update() override;
std::shared_ptr<Component> clone() const override
{
return std::make_shared<TestComponent>(*this);
}
};
class GameObject
{
public:
void addComponent(const Component& comp)
{
components.push_back(comp.clone());
}
// ...
};
int main()
{
GameObject go;
TestComponent comp;
go.addComponent(comp);
}

在这种情况下,您仍然可以创建一个副本,但每个类都必须重写clone方法。


关于shared_ptr的问题:std::shared_ptr是一个智能指针,它在多个所有者之间共享对象的所有权。一个或多个std::shared_ptr拥有的对象只有在共享其所有权的所有std::shared_ptr对象都被销毁时才会被销毁。如果你不需要这种行为,那么std::unique_ptr就存在了,并且会表现得更好。std::unique_ptr为独特所有权建模。一次只能有一个std::unique_ptr对象引用一个对象,当该std::unique_ptr被销毁时,该对象就会被销毁。

任何一种类型的智能指针都可以在这种情况下使用:

  • 如果希望GameObject能够与其他所有者(可能是其他GameObjects(共享其组件的所有权,请使用std::shared_ptr
  • 如果希望GameObject对其组件拥有独占所有权,请使用std::unique_ptr。在这种情况下,GameObject仍然可以允许其他对象访问其组件,但组件的寿命将与GameObject的寿命相关联

要编译代码,只需添加另一个方法,其余的都可以。由于update方法是虚拟的,基类是非抽象的,所以两者都可以调用update而不会出现任何问题。

void TestComponent::addComponent(const TestComponent & tcomp)
{
std::shared_ptr<Component> test = std::make_shared<TestComponent >(tcomp);
components.push_back(test);
}

编辑:对于添加任何组件,派生类或基类,使用以下方式:

void TestComponent::addComponent(std::shared_ptr<Component> comp)
{
components.push_back(comp);
}

最新更新