Reputation: 480
I have following classes:
class A
{
public:
A();
virtual void doSomething() const;
};
class B : public A
{
public:
B();
void doSomething() const;
};
Then I have function:
void putToList(const A &a)
{
a.doSomething(); // this one depends on what was set as argument A or B class (putToList(A()) or putToList(B()))
std::list<A> As;
As.push_back(a);
As.back().doSomething(); //this always calls doSomething from A
}
My question is that whyafter taking from list, the object is A and how to prevent it change type and make it B if object I passed to function was of class B.
Upvotes: 0
Views: 58
Reputation: 42093
This is the nice example of object slicing problem, where instance of B
is being sliced to the instance of A
and thus loses what is specific for B
(see What is object slicing?).
You will not achieve run-time polymorphism of this kind while using a list of objects. You could use a list of pointers instead:
std::list<A*> As;
As.push_back(new B());
As.back()->doSomething(); // method of B is invoked
or yet even better: take advantage of RAII for once again and use smart pointers instead of naked pointers (i.e. A*
like shown in my example).
Upvotes: 3
Reputation: 110658
The type of As
is std::list<A>
. It stores A
objects. If you try to put a B
object in, it will be sliced and you'll get only the A
part of it. Whenever you take an element from the list, it is an A
object and so any function you call on it will be a member function of A
.
There are two ways to get polymorphic behaviour in C++: pointers or references. For example, you could store a pointer to A
in the list:
std::list<A*> As;
As.push_back(&a);
As.back()->doSomething();
Of course, it is preferred to wrap it up in a smart pointer.
To use references, you could use a std::list<std::reference_wrapper<A>>
instead.
Upvotes: 5