I am trying to loop over multiple different child classes of a parent. Ideally I would like to save the child objects in a vector of smart pointers. The following outputs "Update idle" for every call to the method Update. I would like for the call to be the overridden variants of the method. What is the best way of solving this problem?
#include <iostream>
#include <memory>
#include <vector>
class Foo
{
public:
virtual void Update(){
std::cout << "Update idle" << std::endl;
};
};
class Foo1 : public Foo
{
public:
void Update() override
{
std::cout << "Update Foo1" << std::endl;
}
};
class Foo2 : public Foo
{
void Update() override
{
std::cout << Bar() << std::endl;
}
std::string Bar(){
return "Update Foo2";
}
};
int main() {
std::vector<std::shared_ptr<Foo>> vec{
std::make_shared<Foo>(Foo{}),
std::make_shared<Foo>(Foo1{}),
std::make_shared<Foo>(Foo2{})
};
for (auto &&ptr : vec)
{
ptr->Update();
}
}
CodePudding user response:
std::make_shared<T>(args)
creates an new instance of T
, passing args
to T
's constructor, and then returns that instance in a std::shared_ptr<T>
.
As such, your code is not dynamically creating any Foo1
or Foo2
object for the vector
at all. It is creating 3 dynamic Foo
objects, all of which are copy-constructed from temporary Foo
, Foo1
and Foo2
objects.
In other words:
std::make_shared<Foo>(Foo{})
is equivalent to new Foo(Foo{})
std::make_shared<Foo>(Foo1{})
is equivalent to new Foo(Foo1{})
std::make_shared<Foo>(Foo2{})
is equivalent to new Foo(Foo2{})
You actually want the equivalent of new Foo
, new Foo1
and new Foo2
, so use this instead:
std::vector<std::shared_ptr<Foo>> vec{
std::make_shared<Foo>(),
std::make_shared<Foo1>(),
std::make_shared<Foo2>()
};
Even though your std::vector
holds std::shared_ptr<Foo>
elements, but std::make_shared<Foo1>()
will return a std::shared_ptr<Foo1>()
and std::make_shared<Foo2>()
will return a std::shared_ptr<Foo2>()
, this is OK because std::shared_ptr<Foo1>
and std::shared_ptr<Foo2>
are convertible to std::shared_ptr<Foo>
by virtue of the fact that Foo1
and Foo
derive from Foo
.