Ventuaer
Ventuaer

Reputation: 3

Base class parameter in a derived class' method

Here is my code:

class Base
{
    virtual shared_ptr<Base> clone() const = 0;
};
class A : public Base
{
public:
    A(const string &str) {
    _str = str;
    }
    shared_ptr<Base> clone() const
    {
        return make_shared<A>(*this);
    }
private:
    string _str;
};

class B : public Base 
{
public:
    B() { }
    B &AddToStorage(const string &key, Base &&val)
    {
        //_storage[key] = val; ?
        //_storage[key] = val.clone(); ?
        return *this;
    }
    shared_ptr<Base> clone() const
    {
        return make_shared<B>(*this);
    }
private:
    map<string, shared_ptr<Base>> _storage;
};

Notice the class B and it's method AddToStorage. How can I call this function with both class A and B? As in:

B test;
test.AddToStorage("a", A("test1"));
test.AddToStorage("b", A("test2"));
test.AddToStorage("c", B());

And how can I later differentiate between class A and class B when I access _storage (map)?

EDIT: I've tried to implement cloning, but failed - https://www.fluentcpp.com/2017/09/08/make-polymorphic-copy-modern-cpp/ followed this tutorial, but there seems to be an error "no matching function for call to 'A::A(const B&)'"

Upvotes: 0

Views: 131

Answers (2)

n. m. could be an AI
n. m. could be an AI

Reputation: 120059

How can I call this function with both class A and B?

Both std::shared_ptr<A> and std::shared_ptr<B> are convertible to std::shared_ptr<Base>, which is what your function expects, so providing a shared pointer will work.

test.AddToStorage("a", std::make_shared<A>("test1"));
test.AddToStorage("b", std::make_shared<A>("test2"));
test.AddToStorage("c", std::make_shared<B>());

And how can I later differentiate between class A and class B when I access _storage (map)?

In order to differentiate them, you would need to have a virtual function in Base, and (ideally) override it in A and B to do different things. Having a class hierarchy managed with pointers with no virtual functions at all is rather dubious, so you probably should have at least one.

Upvotes: 2

Zoso
Zoso

Reputation: 3465

To add to the other answer. If you compile your code:

test.AddToStorage("c", B());

the errors is pretty helpful:

no viable conversion from 'B' to 'std::shared_ptr<Base>'

What you're passing in is an actual object of B and not a pointer to B. Now one could try changing that to

test.AddToStorage("c", new B());

But that wouldn't compile too since the constructor for shared_ptr here

SHARED PTR CONSTRUCTOR

is marked explicit. So the only way out is to do something like

test.AddToStorage("c", std::make_shared<B>());

As for detecting the types, as the other answer suggests, having a virtual inheritance hierarchy would be a good idea. If you have RTTI enabled (which is usually enabled by default), you could also use something like type_index which is a wrapper over the runtime type_info and can be used to index into containers.

std::unordered_map<std::type_index, std::string> type_names;
type_names[std::type_index(typeid(A))] = "A";

and then later from a

shared_ptr<A> pA;
std::cout<<type_names[std::type_index(typeid(*pA))]<<'\n';

Upvotes: -1

Related Questions