c++ virtual function problem

Everything todo with programming goes HERE.
Post Reply
gss
Average Program
Posts: 74
Joined: Wed Jun 08, 2005 2:25 pm

c++ virtual function problem

Post by gss »

Another noob c++ programming question. I'll ask it without the code first, but if the answer isn't obvious, I'll add the code

I have two classes:
class item (with virtual function display())
class test (derived from item, and with its own version of display())

Then I instantiate a bunch of item objects and a test object and push them all onto a list (list<item> items;) This all works fine. test makes it into the list because it is derived from item.

The problem comes later when I iterate through the list (using "list <item>::iterator i";) When it gets to the test object, it calls item's display() rather than test's display(). The reason I did all of this inheritance and virtual function code was so that i could put test into the items list and have its own display() method called.

It's operating like it thinks test is an item; so it's not dynamically binding test's display() method. Am I doing something wrong? I've verified that the method declarations and definition headers are identical.

Thanks.
-gss
gss
Average Program
Posts: 74
Joined: Wed Jun 08, 2005 2:25 pm

Re: c++ virtual function problem

Post by gss »

OK, simplified my code into the following example app showing the problem.

Code: Select all

#include <iostream>
#include <string>
#include <list>

using namespace std;


class Item
{
  public:
    Item() {}

    virtual void set_name (string new_name) {
      name = new_name;
    }

    virtual void display() {
      cout << "Item: " << name.c_str() << "\n";
    }

  protected:
    string name;
};


class Test: public Item
{
  public:
    Test() {}

    void display() {
      cout << "Test: " << name.c_str() << "\n";
    }
};

int main (int argc, char **argv)
{
  Item *a,*b;
  list <Item> items;
  list <Item>::iterator i;

  a = new Item();
  b = new Test();

  a->set_name("Item");
  b->set_name("Test");

  items.push_back(*a);
  items.push_back(*b);

  cout << "Calling display methods directly\n";
  a->display();
  b->display();

  cout << "\nCalling display methods through the list iterator\n";
  for (i=items.begin(); i != items.end(); ++i) {
    i->display();
  }

}

This results in the output:

Code: Select all

Calling display methods directly
Item: Item
Test: Test

Calling display methods through the list iterator
Item: Item
Item: Test
I expected the last line to read "Test: Test", just like the 2nd line did when b->display() was called directly. I thought that despite the list being a list of "Item"s, when the object referenced is a "test", test's display would be called, but obviously that isn't the case. Any easy way to adjust this to get what I want?

EDIT: I also just tried pulling the items off of the list and referencing them with Item *, trying to re-create the objects as they were before being pushed onto the list, but it still always used Item's display().
User avatar
dlh
Formerly That OS X Guy
Posts: 2035
Joined: Fri Jan 02, 2004 12:05 am
Contact:

Re: c++ virtual function problem

Post by dlh »

Instead of a list of type list<Item>, have a list of type list<Item *>. Here is an explanation from the C++ FAQ.
Generally, objects that are part of an inheritance hierarchy should be passed by reference or by pointer, not by value, since only then do you get the (desired) dynamic binding (pass-by-value doesn't mix with inheritance, since larger derived class objects get sliced when passed by value as a base class object).
gss
Average Program
Posts: 74
Joined: Wed Jun 08, 2005 2:25 pm

Re: c++ virtual function problem

Post by gss »

Ahhh yes, of course. Made the change and it works as expected. Thanks so much!

- gss
Post Reply