Heterogeneous collections of objects in a list.

Started by
9 comments, last by Greenbean 22 years, 6 months ago
I''ve got a c++ problem here, probably standard stuff to someone who knows, help would be much appreciated. You''ve got a collection of objects, they all derive from a base class - lets say they are employee (baseclass), manager, cashier and floorman. Now you stick all these in a list which accepts employee objects (a cool thing you can do in oo design). Then you want to iterate through the list and call a function "calculatePay()" on all of them. This is a virtual function in the employee class, with a standard default implementation, and of the subclasses also derive their own version of calculatePay(). Now typically if you ask cashier in this case to do the "calculatePay()" function it will perform its local version, but it seems in the list that it performs the base class version only :/ Pretty useless then, perhaps its because the list is declared as a list of employee objects. Now I do have extra tags in there that can help me identify the class at run time (ie each object holds an enumerated variable that says its "employee", "cashier" etc. So perhaps theres a way of looking at object at runtime, asking what its tag is and doing some sorta funky casting ie: if(i->getTag() == CASHIER) (cashier*)i->calculatePay(); //probably syntactically wrong else i->calculatePay(); //which would be the default base class, seemingly regardless if the function is virtual or not :/ i being the current object in the list which we are examining. Any thoughts?
Advertisement
You are obviously doing something wrong here. If you are calling a virtual method on a base class pointer, the correct method(the one belonging to the actual object) should be called.
Messing about with RTTI(complier supplied or your own) is extremely ugly.

"A society without religion is like a crazed psychopath without a loaded .45"
--AnkhSVN - A Visual Studio .NET Addin for the Subversion version control system.[Project site] [IRC channel] [Blog]
Hmm ok, I was basing the asumption that it was calling the wrong function on the actions of the debugger. As I step through the code it clearly goes to the version of the function in the base class (which is inline) for an object which is a subclass of the base class. Perhaps its activating the correct code in the subclass, but it doesn''t indicate this with the debugger? I doubt this because it won''t stop at any break points I''ve made in the subclass.

Heres the function declaration in the superclass:

virtual void updateMovement(GameObject object) {/*Do nothing by default*/;}

And the same declaration in the subclass:

virtual void updateMovement(GameObject object);

:/ ?

Did you say the function was inlined in the base class?

That seems to likely to be your problem... If the code is substituted in during compilation, where exactly is the ability to alter the behavior at runtime?
make sure that you are using pointers. You can assign a pointer to a derived to a variable that holds pointers to base. However you can''t really assign a derived to a base variable. It looks like you can but it doesn''t work.
Here is some code that works. Hope this will help.

  #include <list>#include <iostream> class Employee{public:  virtual void calculatePay()  {    cout << "Employee::calculatePay" << endl;  }}; class Manager : public Employee{public:  void calculatePay()  {    cout << "Manager::calculatePay" << endl;  }}; int main(){  list<Employee*> e;  e.push_back(new Employee);  e.push_back(new Manager);  for(list<Employee*>::iterator i = e.begin(); i != e.end(); i++)    (*i)->calculatePay();}  

AB''s code will surely work. I believe the problem of the original poster''s is that you were probably making a list of Employee instead of a list of Employee*. STL containers store their objects "in size", so in order to use contained objects polymorphically, you must use pointers.
Ok, thanks guys - you''re all on the right track and that code works great. I was creating the objects without using pointers. My only concern is that,

e.push_back(new Employee);

will create Employee objects on the memory heap space. I''ve always avoided this due to it being dodgy. I''m not actually using employee objects, they were an anology - but I''m using what I''ve called GameObjects. These contain the mesh, textures, materials etc for the object - ie they each take a big memory hit. Now its necessary that if I am going to use pointers in the list that the scope of the employee object lasts as long as that of the list. Hence the usefullness of using the heap space in memory; but; how do I clear this data when I delete an object from the list? Is there any way to do this safely, efficiently and cleanly?

I don''t mind doing stuff along the lines of overriding the stl with a special list class just for GameObjects (and its subclasses) etc if this would help - but I''m pretty much at a lost to the whole theory of it all, or how this works. Any thoughts? Heres a link where I''ve been getting info on this from, as well as this forum:

http://www.cs.berkeley.edu/~asha/papers_reports/263.htm
Ooops, didn''t login there - just confirming its me.
Imposter!! =) j/k

Yes, you''ll need to handle things yourself. Internally, objects would have been created in the free store anyway (list does this internally). It''s just that now you have the responsibility for deleting things since you''ve new''d them (huh huh, newd).

Here''s a handy template from Scott Meyers in Effective STL:
  // put this in a lib headerstruct DeleteObject {  template<typename T>  void operator () (const T *ptr) const  { delete ptr; }};// if you want to leave everything till the end to delete:for_each (cont.begin (), cont.end (), DeleteObject ());  

This topic is closed to new replies.

Advertisement