我有以下问题:
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
对象。它们都是Component
s。
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);
}
在这种情况下,main
和go
共享单个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);
}