Home > OS >  How to call overridden child methods in a vector
How to call overridden child methods in a vector

Time:12-02

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>()
};

Online Demo

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.

  •  Tags:  
  • c
  • Related