Reputation: 3
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
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
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
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