Polymorphism and List problem

Feb 11, 2012 at 9:59am
Hi All,

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 doesnt .Any ideas..
I am learning polymorphism so also have commented few questions related to it on the lines of code below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
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 mehtod
{

	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;
  }

}

void main()
{
methodCall();
}
Last edited on Feb 11, 2012 at 3:15pm
Feb 11, 2012 at 10:20am
[code] "Please use code tags" [/code]
_ ¿why virtual destructor?
So it calls the proper destructor.
Test this:
1
2
Base *obj = new Derived;
delete obj;


_ does the overrided method also has to be have the keyword 'virtual'?
No, you don't need to write it. ¿why would you want to do that?

_ If you declare a class inside a function, then it will only be visible inside that function.
You can't create B or C objects outside that function, because the compiler will not know what they are.

_ As to why you don't observe the polymorphic behaviour
ist<A> listOfAs; has objects of type A. They were sliced from a B and a C, but they are A.
You would observe if you have a pointer or a reference of the base type pointing to the derived type.

_ main must return int
Feb 11, 2012 at 10:21am
Please use code tags.

why virtual destructor ?

Because if you don't put your destructor as virtual, an object of type A* which hold in fact an object of type B* will use A's destructor and this could lead to memory leaks.

does the overrided method also has to be have the keyword 'virtual'

No but it helps to make your code clearer. In c++11 you can put the keyword override at the end of the method signature to make sure it's an overrided method(cause a compilation error if the method doesn't override parent methods).

I am declaring the objects as in 1st scenario but how about 2nd scenario, is this suppose to work too ??

You can't assign base type pointer to child type pointer unless you use static_cast or dynamic_cast( http://www.cplusplus.com/doc/tutorial/typecasting/ )

cout << *it.say() << endl;

This sould not even compile, as . operator have higher precedance than * use it->say() and don't put cout and endl, your "say" method returns void and you can't print void.

It doesn't because listOfA dosn't contains polymorphic type, the method call is resolved at compile time. You should make listOfA a list of A* and allocate them with new for example to make it work. Dynamic call only work on pointer or references.
Feb 11, 2012 at 12:03pm
In order to experience polymorphic behaviour you need to call your member functions through a pointer or a reference. You are not doing that. Here you place the objects themselves into your list, NOT pointers:
1
2
listOfAs.insert(it,*aB);
listOfAs.insert(it,*aC);

Consequently you are not calling the member functions through pointers here:
1
2
3
4
for(it=listOfAs.begin(); it!=listOfAs.end(); it++)
{
    cout << *it.say() << endl; // *it is NOT a pointer!
}

The way to do this is to make a list of pointers:
1
2
3
4
5
6
7
8
9
list<A*> listOfAPointers;
list<A*>::iterator it;

// ...

for(it=listOfAPointers.begin(); it!=listOfAPointers.end(); it++)
{
    cout << (*it)->say() << endl; // *it is a pointer!
}
Last edited on Feb 11, 2012 at 12:04pm
Topic archived. No new replies allowed.