list of polymorphic objects
Asked Answered
G

3

5

I have a particular scenario below. The code below should print 'say()' function of B and C class and print 'B says..' and 'C says...' but it doesn't .Any ideas.. I am learning polymorphism so also have commented few questions related to it on the lines of code below.

class A
{
public:
// A() {}
    virtual void say() { std::cout << "Said IT ! " << std::endl; }
    virtual ~A(); //why virtual destructor ?
};

void methodCall() // does it matters if the inherited class from A is in this method
{
    class B : public A{
    public:
        // virtual ~B(); //significance of virtual destructor in 'child' class
        virtual void say () { // does the overrided method also has to be have the keyword  'virtual'
            cout << "B Sayssss.... " << endl; 
        }
    };
    class C : public A {
    public:
        //virtual ~C();
        virtual void say () { cout << "C Says " << endl; }
    };

    list<A> listOfAs;
    list<A>::iterator it;

    # 1st scenario
    B bObj; 
    C cObj;
    A *aB = &bObj;
    A *aC = &cObj;

    # 2nd scenario
    //  A aA;
    //  B *Ba = &aA;
    //  C *Ca = &aA; // I am declaring the objects as in 1st scenario but how about 2nd   scenario, is this suppose to work too?

    listOfAs.insert(it,*aB);
    listOfAs.insert(it,*aC);

    for (it=listOfAs.begin(); it!=listOfAs.end(); it++)
    {
        cout <<  *it.say()  << endl;
    }
}

int main()
{
    methodCall();
    return 0;
}
Gyrus answered 11/2, 2012 at 16:7 Comment(0)
T
4

Your problem is called slicing and you should check this question: Learning C++: polymorphism and slicing

You should declare this list as a list of pointers to As:

list<A*> listOfAs;

and then insert these aB and aC pointers to it instead of creating copies of objects they are pointing to. The way you insert elements into list is wrong, you should rather use push_back function for inserting:

B bObj; 
C cObj;
A *aB = &bObj;
A *aC = &cObj;

listOfAs.push_back(aB);
listOfAs.push_back(aC);

Then your loop could look like this:

list<A*>::iterator it;
for (it = listOfAs.begin(); it != listOfAs.end(); it++)
{
    (*it)->say();
}

Output:

B Sayssss....
C Says

Hope this helps.

Tirado answered 11/2, 2012 at 16:14 Comment(4)
Actually using a container of naked pointers is a pandora's wasp nest, though, and any number of things can go wrong...Interposition
I agree. But in this case I consider it more appropriate to use naked pointers so that he better understands what's going there.Tirado
in the above scenario do i have to also take care of List elements once i used it.. Do i have to delete it or something ???Gyrus
In this list there are references to automatic variables (bObj and cObj), so no. You don't delete it since you hadn't allocated it.Tirado
I
2

Polymorphism of virtual class hierarchies only works through references or pointers to a base subobject:

struct Der : Base { /* ... */ };

Der x;

Base & a = x;

a.foo();   // calls Der::foo() from x

The function foo is dispatched polymorphically if it is a virtual function in Base; the polymorphism refers to the fact that while you are calling a member function of an object of type Base, the function that actually gets called may be implemented in the class Der.

Containers can only store elements of a fixed type. In order to store a polymorphic collection, you could instead have a container of pointers to the base class. Since you need to store the actual objects elsewhere, lifetime management is non-trivial and best left to a dedicated wrapper such as unique_ptr:

#include <list>
#include <memory>


int main()
{
    std::list<std::unique_ptr<Base>> mylist;

    mylist.emplace_back(new Der1);
    mylist.emplace_back(new Der2);
    // ...

    for (p : mylist) { p->foo(); /* dispatched dynamically */ }
}
Interposition answered 11/2, 2012 at 16:14 Comment(1)
1 : What does this "Containers can only store elements of a fixed type." means ?? 2 : "you could instead have a container of pointers to the base class" Do you mean 'list<A *> listOfAs' instead of 'list<A> listOfAs;'Gyrus
A
0

list::iterator it; B bObj; C cObj; A *aB = &bObj; A *aC = &cObj; listOfAs.insert(it,*aB);

Do you not need to initialize "it" ? I believe you should do it = listOfAs.begin(); before starting to insert.

Antitype answered 11/2, 2012 at 17:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.