roslav
roslav

Reputation: 480

List converts class to parent

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

Answers (2)

LihO
LihO

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

Joseph Mansfield
Joseph Mansfield

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

Related Questions