2

I have struct A and struct B, how could I achieve polymorhism for this case when I need to store the objects in a vector in f and it has parameter of base class A

#include <iostream>
#include <vector>
#include <memory>

using namespace std;

struct A
{
    void virtual print()
    {
        std::cout << "a\n";
    }
};

struct B : public A
{
    
    void print() override
    {
        std::cout << "b\n"; 
    }
};

void f(A& a)
{   
    // here I don't know what kind of object is that's why I use A
    std::vector<std::unique_ptr<A>> vecA;
    vecA.emplace_back(std::make_unique<A>(a));

    vecA[0]->print();
    // I want to print b
}

int main()
{   
    B b;
    f(b);

    return 0;
}
tadman
  • 208,517
  • 23
  • 234
  • 262

1 Answers1

3

If you are given a reference to a polymorphic A, and you need to store a copy of it while preserving the dynamic type, that calls for cloning:

struct A
{    // don't forget the virtual destructor if you're storing A polymorphically
    virtual ~A() = default;

    void virtual print() const
    {
        std::cout << "a\n";
    }

    virtual std::unique_ptr<A> clone() const {
        return std::make_unique<A>(*this);
    }
};

// add the corresponding clone() override in B:
struct B {
    // ...
    std::unique_ptr<A> clone() const override {
        return std::make_unique<B>(*this);
    }
};

// if we're going to copy it, then it should be cosnt&
void f(const A& a)
{   
    std::vector<std::unique_ptr<A>> vecA;
    vecA.emplace_back(a.clone());
    // prints b
    vecA[0]->print();
}

If you always passed A around in a std::unique_ptr, you could also avoid the whole clone() problem and simply do:

void f(std::unique_ptr<A> a)
{   
    std::vector<std::unique_ptr<A>> vecA;
    vecA.push_back(std::move(a));
    // prints b
    vecA[0]->print();
}

See live example at Compiler Explorer

The solution ultimately depends on whether you need to support copying A, or whether you can use it as a move-only type.


See Also

Jan Schultke
  • 17,446
  • 6
  • 47
  • 96