views:

143

answers:

3

Okay, I'm writing a game that has a vector of a pairent class (enemy) that s going to be filled with children classes (goomba, koopa, boss1) and I need to make it so when I call update it calls the childclasses respective update. I have managed to create a example of my problem.

#include <stdio.h>
class A{
    public:
        virtual void print(){printf("Hello from A");}
};

class B : public A{
    public:
        void print(){printf("Hello from B");}
};


int main(){
    A ab = B();
    ab.print();
    while(true){}
}

Output wanted: "Hello from B" Output got: "Hello from A"

How do I get it to call B's print function?

+13  A: 

Polymorphism only works on pointers and references. If you assign a B to an A, it becomes an A and you lose all B-specific information, including method overrides. This is called "slicing"; the B parts are "sliced" off the object when it is assigned to an object of a parent class.

On the other hand, if you assign a B* to an A*, it looks like an A*, but is still really pointing to a B, and so the B-specific information remains, and B's virtual overrides will be used.

Try:

int main(){
    A* ab = new B();
    ab->print();
    delete ab;
    while(true){}
}

The same also applies to assigning a B to an A& (reference-to-A), e.g.

int main(){
    B b;
    A& ab = b;
    ab.print();
    while(true){}
}
Tyler McHenry
This worked. Thank you.
William
+1: Wow, didn't know it.
Simon
Both of you (from your post histories) seem to come from a Java background. It's important to remember that in Java, all objects are really references (in the Java sense, which is really somewhere between a C++ pointer and a C++ reference), and everything is virtual, so polymorphism always works. In C++, objects are value types, and so assigning two objects really does assign the value of the right side to the left, rather than making the left side be a reference to the same object as the right. This means slicing can happen, since an `A` object simply has nowhere to store `B`'s extra info.
Tyler McHenry
+3  A: 

Your virtual keyword is correctly placed, you need to use pointers or references though.

Brian R. Bondy
A: 

You need to call the parent's update method before any processing by the descendant classes:

struct Base_Class
{
  virtual void update(void)
  {
    cout << "Updating Base_Class.\n";
  }
};

struct Goomba : public Base_Class
{
  void update(void)
  {
     // Invoke the parent method first.
     Base_Class::update();

     // Perform Descendant operations
     cout << "Updating Goomba\n";
  }
};

Here is the implementation:

#include <iostream>
using std::cout;

void Update_Player(Base_Class& b)
{
  b.update();
  return;
}

int main(void)
{
   Goomba g;
   g.update();

   Goomba g2;
   std::vector<Base_Class *> container;
   container.push_back(&g);
   container.push_back(&g2);

   std::vector<Goomba>::iterator iter;
   for (iter =  container.begin();
        iter != container.end();
        ++iter)
   {
       Update_Player(*(*iter));
   }

   return 0;
}
Thomas Matthews
If you want to do this, it's better to have Update *not* be virtual, but instead have the base class Update be the only function of that name, then that calls the virtual DoUpdate function where appropriate. Much easier then, because then implementors of child classes don't need to remember when to call the base class update function.
dash-tom-bang