Inheritance, subsumption, and constructing (C++ question)

If you are a new Irrlicht Engine user, and have a newbie-question, this is the forum for you. You may also post general programming questions here.
Baiame
Posts: 41
Joined: Sun Oct 15, 2006 11:33 am

Inheritance, subsumption, and constructing (C++ question)

Post by Baiame »

Hello. I've been looking around the internet on this subject for a few hours, with little results.

In my game (probably as in any other), I'm going to have a list containing the base class of all existing entities. Each loop, I'll iterate through the list, calling an update() function. My problem is with downcasting and/or construction. Suppose I have:

Code: Select all

class Shape
{
public:
       int xPos;
       int yPos;
       Shape(int x=0, int y=0);
};

Shape::Shape(int x, int y)
{
 xPos=x;
 yPos=y;
}

class ThreeD : public Shape
{
public:
       int zPos;
       int getZ();
       ThreeD(int x=0, int y=0, int z=0);
};

ThreeD::ThreeD(int x, int y, int z):Shape(x, y)
{
 zPos=z;
}

int ThreeD::getZ()
{
 return zPos;             
}
And later, in the main function:

Code: Select all

Shape* shapePointer=new ThreeD(10, 10, 10);
This seems to be the only way I can create an instance of the ThreeD class, while still using a pointer of the base class type (so that I could put it in a list). Of course, to then call:

Code: Select all

cout<<shapePointer->getZ();
Won't work. I read about something called "downcasting", so I did this:

Code: Select all

ThreeD* threeDpointer=(ThreeD*)shapePointer;
then I can call:

Code: Select all

cout<<threeDpointer->getZ();
Which works fine. But that doesn't represent the kind of abstraction I need for my actual game. You see, I need a complex hierarchy of classes, and each class that represents a kind of entity that will exist in the world needs an update() function.

The list class can't just call the update function without downcasting (as far as I know). But downcasting is impossible, because the list object isn't aware of the children of the class that it's pointing to; it's just pointing to a base class instance. Could someone please explain how I'd do it, or point me towards such an explanation?
Luke
Admin
Posts: 449
Joined: Fri Jul 14, 2006 7:55 am
Location: Australia
Contact:

Post by Luke »

There are lots of methods, but as you're talking about an update() function, you might want to try this.

Code: Select all

class Shape
{
public:
       int xPos;
       int yPos;
       Shape(int x=0, int y=0);

       virtual int getZ() {return 0}
/*
or you can go:
      virtual int getZ()=0;
*/
};

Shape::Shape(int x, int y)
{
 xPos=x;
 yPos=y;
}

class ThreeD : public Shape
{
public:
       int zPos;
       virtual int getZ();
       ThreeD(int x=0, int y=0, int z=0);
};

ThreeD::ThreeD(int x, int y, int z):Shape(x, y)
{
 zPos=z;
}

int ThreeD::getZ()
{
 return zPos;             
}
Baiame
Posts: 41
Joined: Sun Oct 15, 2006 11:33 am

Post by Baiame »

Thanks Luke.

That seems a good method for my update() functions. However, I do think I'll need some communication between different entities; they can't be completely self-controlling (suppose I want bullets to physically affect props, the bullet class would have a function that calls the hit function of the object that was struck).

Now, was I to use that method for all other functions that different entity objects may need to call, my base class would be full of pure virtual functions. I don't know if that's standard, but is there a more suiting method?
Warchief
Posts: 204
Joined: Tue Nov 22, 2005 10:58 am

Post by Warchief »

Baiame wrote: Now, was I to use that method for all other functions that different entity objects may need to call, my base class would be full of pure virtual functions. I don't know if that's standard, but is there a more suiting method?
Indeed. Thats the reason I wouldn't go for that solution. If you just want to update them, why should you need to call specific functions?

Code: Select all

// Class for every object that need an update each frame
class IUpdate {
   void Update() = 0;
}

class CUpdatesManager {
    bool RegisterObject( IUpdate *objPtr ) {
       // Insert objPtr into the container
    }
    void UnregisterObject( IUpdate *objPtr  ) {
       // Remove objPtr from the container
    }
    void Update() {
       // for every object in the container
       object->update(); // leave the object update itself
    }
}

// Btw i wouldn't add x and y here
class IShape : IUpdate {
     // Methods for all shapes
     void Scale( short times ) = 0; // just an example
}

class ThreeD : public IShape {
    int m_x;
    int m_y;
    int m_z;

   // Needs to define this
   void Scale( short times ) {
       // Scale myself
   }
   // And this
   void Update() {
       // If moving, update the position
   }
}

Code: Select all

void  somewhere() {
     // Would need a manager
     CUpdateManager manager;

     // Create the specific instances
     ThreeD *sPtr = new ThreeD;

     // Register as an object to update
     manager.RegisterObject( sPtr );

     while ( inGame )
     {
         manager.Update(); // Calls every object to update
     }

     // :)
     delete sPtr;
}
Within ThreeD::Update() you may call what you need because it's inside ThreeDs scope.
Warchief's Warboard 3D Now hotseat release
Luke
Admin
Posts: 449
Joined: Fri Jul 14, 2006 7:55 am
Location: Australia
Contact:

Post by Luke »

Warchief that might be a bit tricky for Baiame, that would probably be a pretty steep learning curve.


Baiame, it’s hard to explain, there are lots of different methods and styles used

One method might be to have your base classes have the general functions for that type of class as pure virtual functions.

These general functions could then call the specific functions for each class, as would be in the right scope.

This is mainly for the update function thing.
Warchief
Posts: 204
Joined: Tue Nov 22, 2005 10:58 am

Post by Warchief »

Luke wrote:Warchief that might be a bit tricky for Baiame, that would probably be a pretty steep learning curve.
If this is true he should be learning c++ & oop before he can start using irrlicht for anything more thatn compiling the tutorials :)
Warchief's Warboard 3D Now hotseat release
Baiame
Posts: 41
Joined: Sun Oct 15, 2006 11:33 am

Post by Baiame »

Thanks Warchief, but as Luke said, that's a little tricky for me. I kind of see what you did there, but I certainly wouldn't be confident enough to use it myself. To be honest, I'm in no position to start writing efficient code at the moment.

I think your point about "learning c++ & oop" is a bit unfair. I know the basics of c++ and OOP; but it's a matter of degree. Does one really need to become an expert programmer before working on a game? Two things I must point out. Firstly, I'm not actually trying to program the game yet, I'm just working out how I can do the basics, and figuring out my class design. Secondly, I actually began programming with games; it's the way I'm used to learning how to program.

Luke, I was already aware of the method you state in your last post (using pure virtual functions in the base class). I just thought there might be an equally easy, superior way, but I guess not. I'll stick with the method you suggested for the time being. Thanks all.
Warchief
Posts: 204
Joined: Tue Nov 22, 2005 10:58 am

Post by Warchief »

Just quoting you:
Which works fine. But that doesn't represent the kind of abstraction I need for my actual game. You see, I need a complex hierarchy of classes, and each class that represents a kind of entity that will exist in the world needs an update() function.

Code: Select all

// As your quote
// <<a kind of entity that will exist in the world needs an update() function.>>
class IUpdate {
   virtual void Update() = 0;
}
The list class can't just call the update function without downcasting (as far as I know).
There's a way to do it, but it's not clean.

Code: Select all

switch ( theEntityType ) {
    case typeA:  
    {
       A *aPtr = (A*)object;
    }
  // ...
}
But downcasting is impossible, because the list object isn't aware of the children of the class that it's pointing to; it's just pointing to a base class instance.

Indeed, CUpdatesManager is just a class with a list/array/container. RegisterObject and UnregisterObject are myList.insert and myList.remove.

Could someone please explain how I'd do it, or point me towards such an explanation?
Lets go easier:

Code: Select all

class IUpdate {
public:
   virtual void Update() = 0;
}

class Shape : public IUpdate {
   int x;
   int y;
  Shape( int _x, int _y ) {
    x = _x;
    y = _y;
  }
public:
   void Update() {
       cout << "I'm updating! [" << x << ", " << y << "] << endl;
   }
}

main() {
   IUpdate *array[2];
   array[0] = new Shape(0,0);
   array[1] = new Shape(1,1);

   while( true ) {
      for( int i=0; i<2; ++i ) {
         // YOU CAN CALL UPDATE ON SHAPES EVEN WITHOUT KNOWING 
         // THEY ARE SHAPES. IT'S JUST BECAUSE THEY ARE IUpdate
         array[i]->Update();
      }
   }
}
Warchief's Warboard 3D Now hotseat release
Baiame
Posts: 41
Joined: Sun Oct 15, 2006 11:33 am

Post by Baiame »

Thanks Warchief, but unless I am mistaken, that's essentially the same method as Luke first suggested (a pure virtual function in the base class), except that you put it in a separate class inherited by all entities (which is probably the way I'll do it; an Entity class that has only pure virtual functions as its members). Thanks again Warchief and Luke.
Warchief
Posts: 204
Joined: Tue Nov 22, 2005 10:58 am

Post by Warchief »

Think Luke suggested make every method virtual even when shape base class wont need it (that's the case of GetZ), so you can use them somewhere out of the Shape scope to update shapes. That's not the same approach than having a unique Update method that is different for every shape.
Warchief's Warboard 3D Now hotseat release
Baiame
Posts: 41
Joined: Sun Oct 15, 2006 11:33 am

Post by Baiame »

^ Oh, yeah, I see what you mean now. But I think he was just trying to convey the concept of pure virtual functions, while changing my source as little as possible. It doesn't matter anyway, you guys have provided a solution.

I still have a (totally irrelevant) question, though. How does one go about resolving static and dynamic data? For example, suppose you need some kind of string to hold the names of entities that can be picked up and added to your inventory. Storing a variable containing the name in each entity instance clearly uses alot of memory; and it shouldn't be necessary, as the same names will be repeated.

So what kind of reference in each entity class instance do you use, and what kind of data structure do you store such static data in? Please excuse my ignorance. I can think of a few possibilities (for example, static arrays containing static data created at game startup, with a short variable per entity class child to refer to an array), but they all seem flawed. Does anyone have any suggestions?

EDIT- Maybe I should go into more depth about what I think my options are. Basically, what I need is a way to store two different things: defaults for entity instantiation (i.e., for a physical object, the entity manager would need to know the entity type's mass), and static data (such as the string representing an inventory entity's name). I already know that the two will be exactly the same data, and no doubt stored in the same data structure. But what is that data structure?

These are the two ways I thought of. The first is to have a class hierarchy mimicking that of the dynamic entity class hierarchy, but for storage of static data, and each entity type only needs one instance of these classes. Each dynamic entity object has a pointer to its static counterpart. As an example, the "static inventory entity" class would have a string representing the entity's name; this string is not present in the "dynamic" entity hierarchy. Every time you need to know the entity's name, you'd have to access the static entity object's functions through the dynamic entity object's pointer.

Now, this would be quite neat, consistent, and easy to understand. But I suspect much proccessor overhead (remember, I'm using pure virtual functions in base classes to access the functions of lower-hierarchy classes). Having to go through a pointer and access a virtual function every time you need to access a piece of static data strikes me as inefficient. Here's another way I thought of.

Have a bunch of static arrays containing structures, one for each class that needs static data. For example, there would be a "static inventory" array, and the structures in that array would contain a string variable for each inventory entity type's name. Each class in the dynamic entity hierarchy has either a short or byte variable that is an array reference; an object might have several such references in total.

I suspect this way would be faster, but it's very non-OO. I'd be very grateful for any input.
Warchief
Posts: 204
Joined: Tue Nov 22, 2005 10:58 am

Post by Warchief »

A pointer to the static data or an indexed array both may work. Even the duplicated data in favor of performance instead of memory consumption. But anyway, i would recommend that if you are making the high level part of the game (player inventory is high level) go with the OO solution. Indexed array is OO as well as the pointer. It just stores the attributes of the dynamic object, no matter if it's a direct pointer or a key for a container.
Warchief's Warboard 3D Now hotseat release
Baiame
Posts: 41
Joined: Sun Oct 15, 2006 11:33 am

Post by Baiame »

^ Thanks alot Warchief, think I'll use the "indexed arrays". Maybe using totally different data structures for static and dynamic data is less programmer error-prone anyway.
stodge
Posts: 216
Joined: Fri Dec 05, 2003 5:57 pm

Post by stodge »

Check out the Visitor design pattern. Sounds like it might work for you.
What does the debugger tell you? You did use the debugger, didn't you?
Saturn
Posts: 418
Joined: Mon Sep 25, 2006 5:58 pm

Post by Saturn »

Visitor? How is that? Too me the proper pattern looks more like flyweight. But this is of no help to throw pattern names around here. ^^
Post Reply