[C++] using a std::list for derived classes

Started by
3 comments, last by Silvo 17 years, 10 months ago
G'day! I was looking at the third Enginuity article, and he uses classes derived from his Task class, which I perfectly understand (the concept, that is), but later on he has a task manager (he calls his Kernel), which has std::lists of the Task base class, not any derived class. He did say that you you need inherit from the base Task class, and as he made two of the functions pure virtual, it's very obvious. I tried to mimic this set up using std::list, and made up some simple classes, but it doesn't work as his is supposed to. The source:
#include <list>
#include <iostream>

using namespace std;

class John {
public:
	virtual void Write() {
		cout << "John here!";
	};
};

class Jeff : public John {
public:
	virtual void Write() { 
		cout << "Jeff here!";
	};
};

class Jerry : public John {
public:
	virtual void Write() {
		cout << "Jerry here!";
	};
};



int main() {
	list< John > myList;
	John john;
	Jerry jerry;
	Jeff jeff;


	myList.push_back(john);
	myList.push_back(john);
	myList.push_back(john);
	myList.push_back(jeff);
	myList.push_back(john);

	int i = 0;
	for (list< John >::iterator it = myList.begin(); it != myList.end(); it++) {
		cout << "myList[" << i << "].Write();" << endl;
		it->Write();
		cout << endl;
		i++;
	}


	return 0;
}
The output is as follows:
myList[0].Write();
John here!
myList[1].Write();
John here!
myList[2].Write();
John here!
myList[3].Write();
John here!
myList[4].Write();
John here!

The problem is, myList[3] is actually a Jeff, not a John, so shouldn't it print "Jeff here!" instead?? I did notice that when I hovered over Write() in it->Write() in the for-loop, it said "virtual void John::Write(void)" which makes me think that it->Write() is calling John::Write of jeff, not Jeff::Write, and I do remember something in my book about that... but I've lent that to my friend... Anywho, can anyone explain this anomoly? (spelling?)
Advertisement
Changing the main function to this will fix it:
int main() {	list< John* > myList;	John john;	Jerry jerry;	Jeff jeff;	myList.push_back(&john);	myList.push_back(&john);	myList.push_back(&john);	myList.push_back(&jeff);	myList.push_back(&john);	int i = 0;	for (list< John* >::iterator it = myList.begin(); it != myList.end(); it++) {		cout << "myList[" << i << "].Write();" << endl;		(*it)->Write();		cout << endl;		i++;	}	return 0;}


Ofcourse, a list of pointers is not the same thing, but I believe that the way you did it, you were suffering from the so called slicing problem (look it up)
Could it be possible that the list in his example uses pointers?

The thing is that since you're storing actual objects of type John (you should pick something like Employee or something...), when your other types are pushed on the list they get COPIED, and sliced down to the type John (as that's what the list is holding). By storing pointers, the pointer is copied, but it's still pointing to the initial object, thus displaying the right message.

Hope this helps
Thanks alot, that works perfectly.

Actually, now that I look at Enginuity's way of doing it, it is actually a std::list< CMMPointer< ITask > >, and I think that the CMMPointer is just a special kind of pointer he made, so that would make sense.

I am looking up the slicing problem thingo now, but I do remember something about pointers and derived classes from that book now, it's just that when I was reading it, pointers scared me, so I don't think I picked it all up...

Thanks!
xEricx:

You must have posted while I was typing my reply. Yes, I'm pretty sure you hit the nail exactly on the head, that makes alot of sense and in the deep recesses of my brain I remember reading something like that. this site under the heading "Prefer Passing Parameters by Const Reference" briefly talks about the slicing problem, and now everything works.

I don't like pointers, but I'm going to have to face my phobia and use them...

[Edited by - Silvo on June 29, 2006 8:00:31 PM]

This topic is closed to new replies.

Advertisement