Thread: Polymorphism via a vector of objects

  1. #1
    Registered User
    Join Date
    Aug 2009
    Location
    Scotland
    Posts
    5

    Polymorphism via a vector of objects

    I am working on a simple game loop.

    The idea is to have a parent game object from which all other objects are derrived. The idea behind this is so the class can be expanded and reimplemented for objects such as detail props, players, vehicles, pickups etc; all which can pass around IDs to each other and have their own unique step functions.

    Here is a condensed form of my current code with only what applies to the problem:
    Code:
    #include <iostream>
    #include <vector>
    #include <cmath>
    #include <windows.h>
    
    /*
      Parent class to all objects which are part of the main game loop.
      Examples:
      static props
      physics props
      players
      enemies
      vehicles
      explosion handlers
      triggers
    */
    class CgameObject{
    public:
      long x,y; //location
      bool awake, visible;
    
      //constructor
      CgameObject(long setX,long setY){
        x = setX;
        y = setY;
        visible = true;
        awake = true;
      }
    
      virtual void step(){};
    };
    
    class CmotionObject : public CgameObject{
    public:
      double direction, //angle in degrees going anticlockwise from the +ve x axis
      speed, //speed in pixels/frame along the direction (+ve or -ve)
      vSpeed, //speed in pixels/frame along the y axis, down being +ve
      hSpeed; //speed in pixels/frame along the x axis, right being +ve
    
    public:
      //constructor
      CmotionObject(long setX,long setY):CgameObject(setX,setY){
        vSpeed = 0;
        hSpeed = 0;
        speed = 0;
        direction = 0;
      }
    
      virtual void applyMotion(){
        x += (long)hSpeed;
        y += (long)vSpeed;
      }
    };
    
    using namespace std;
    unsigned int i;
    unsigned long frameCount;
    
    //#include "classes/gameObject.h"
    //#include "classes/motionObject.h"
    vector <CgameObject> gameObjects;
    
    class Cplayer : public CmotionObject{
    public:
      Cplayer(long setX,long setY):CmotionObject(setX,setY){};
    
      //do this every frame
      virtual void step(){
        applyMotion();
        cout << "player is at " << x << endl;
        if(x < 100){
          if(x >= 100) cout << frameCount << ", player has reached the finishing line\n";
          hSpeed = 0; //stop moving
        }
      }
    
    };
    
    int main(){
      frameCount = 0;
    
      gameObjects.push_back(Cplayer(0,30));
    
      while(true){
        for(i = 0;i < gameObjects.size();i ++){
          gameObjects[i].step();
        }
        frameCount ++;
        cout << "frame #" << frameCount << " completed\n";
        Sleep(100); //10 fps
      }
      return 0;
    }
    Now, the issue I have is the functions do not seem to be overridden by CmotionObject and Cplayer, when I try to step the game objects it calls the step of the CgameObject class, and not Cplayer in this case - so the whole functionality of the program is completely in jeopardy.

    Is this the intended way to do something like this? And in what way have I done it wrong? Thanks and I look forward to the responses.

    Also, whilst programming this I noticed things that should be easier to implement. Such as applyMotion() each frame. Is there a way I can make CmotionObject have a step event which calls applyMotion, but step events of CmotionObject's child classes will not overwrite it - but simply perform before it? (or after it)

    edit:
    A litte more of what I am on about:
    If I try to for example: change a variable in an object of the player class, such as player name... it would work something along the lines of gameObjects[0].name = inputFromSomewhere. But it cannot be done because gameObjects is a vector of type CgameObject... I thought the point with polymorphism was that I could do things like that and it would work, unless I landed on an object which was not of the player sub class, such as gameObjects[31].name, if the object of id 31 was a pickup or something. Also, my sleeping system would simply be implemented within the main loop, should I add another data structure of flags? Also, if items are removed from the vector, their indexes will not be preserved and that will ruin things, should I find another way to go about this or is there something else I need to add to get proper functionality when I begin to program something more interesting?

    edit:
    title isn't very good. If a mod sees this can you change it to Polymorphism within objects in a vector? Or whatever you think is more appropriate, thanks and sorry to have to ask that.
    Last edited by Bozebo; 01-20-2010 at 03:55 AM. Reason: more to say

  2. #2
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    The only way you can achieve polymorphic calls in C++ is via pointers or references to objects. Otherwise the compiler needs to specifically know what type the object is, in order to invoke the correct version of the virtual function.

    One way around it is to use a vector<CgameObject *>, and store the addresses of objects in the vector. The catch is that you, the programmer, must ensure the individual objects are not destroyed while their address is stored in the vector (otherwise the calling of member functions, or accessing of any members, yields undefined behaviour).
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  3. #3
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    But, on the other hand, smart pointers will help you with the last issue, making it a viable solution together. So store pointers in the vector.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  4. #4
    Registered User
    Join Date
    Aug 2009
    Location
    Scotland
    Posts
    5
    Quote Originally Posted by grumpy View Post
    The only way you can achieve polymorphic calls in C++ is via pointers or references to objects. Otherwise the compiler needs to specifically know what type the object is, in order to invoke the correct version of the virtual function.

    One way around it is to use a vector<CgameObject *>, and store the addresses of objects in the vector. The catch is that you, the programmer, must ensure the individual objects are not destroyed while their address is stored in the vector (otherwise the calling of member functions, or accessing of any members, yields undefined behaviour).
    OK I tried that (addmitedly initially just by sticking in the * and seeing what happens) and I am running into problems:

    cannot convert parameter 1 from 'Cplayer' to 'CgameObject *const &'
    edit: solved that now. See far below.

    Chich makes a bit of sense, now classes derrived from CgameObject are not valid entries in the vector?
    And you picked up on my second issue before I edited it within my original post, I need some array of object indexes and object ids. So the ids stay the same all the time and the indexes are updated when needed? Allowing my programming of objects within the game such as ai, vehicles, pickups etc to collect ids of other objects and refer to them to cause reactions to events etc.

    edit:
    But, on the other hand, smart pointers will help you with the last issue, making it a viable solution together. So store pointers in the vector.
    Can I catch the issue before a run time error occurs? Because of course if objects like pickups are destroyed whilst an AI is moving that way, the ai will need to know it no longer exists and change it's plan - which is an example of when it would normally be looking out-of-bounds, not only that but vectors don't leave empty gaps so all indexes higher than it will go down by 1 when it is destroyed - is that not using up resources? I thought a nice way would be to have a pool of items/objects which can be destroyed which simply lay inactive when they are not all used? But that is probably not a recognised way to handle the situation and certainly is a lazy one.

    edit: (re-edited)
    OK I fixed that error, I forgot to use -> to call the step event.
    Now, the player's step event is being called correctly. But I have an odd issue which I think is due to my type choices, x and y are longs, hSpeed is a double. If hSpeed is a small number like 1, 30, 17 - the player will stay at 1, 30 or 17 x, however if I set it to 100 then the player moves correctly: 100,200,300,400 (each frame)... is that unusual?
    OK, the small issue above was a silly problem in my player event step code, it's not a fundamental flaw in the program, and I fixed it now.
    Last edited by Bozebo; 01-20-2010 at 04:16 AM.

  5. #5
    Registered User
    Join Date
    Aug 2009
    Location
    Scotland
    Posts
    5
    OK, I have everything I was attempting working. Thanks for the help.

    Now I am going to take a few steps back and work on an engine class which organises the objects and contains the variables which are currently global - sorting them out correctly and making functions to work with them.

  6. #6
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by Bozebo View Post
    Can I catch the issue before a run time error occurs? Because of course if objects like pickups are destroyed whilst an AI is moving that way, the ai will need to know it no longer exists and change it's plan - which is an example of when it would normally be looking out-of-bounds, not only that but vectors don't leave empty gaps so all indexes higher than it will go down by 1 when it is destroyed - is that not using up resources? I thought a nice way would be to have a pool of items/objects which can be destroyed which simply lay inactive when they are not all used? But that is probably not a recognised way to handle the situation and certainly is a lazy one.
    Recall that your original solution was to store local objects in the vectors. When you remove an element, or the vector goes away, then and only then, is the object or objects destroyed.
    Smart pointers (shared pointers) are they same. They delete the resource they point to if, and only if, the last local object pointing to the resource is destroyed.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  7. #7
    Registered User
    Join Date
    Aug 2009
    Location
    Scotland
    Posts
    5
    Quote Originally Posted by Elysia View Post
    Recall that your original solution was to store local objects in the vectors. When you remove an element, or the vector goes away, then and only then, is the object or objects destroyed.
    Smart pointers (shared pointers) are they same. They delete the resource they point to if, and only if, the last local object pointing to the resource is destroyed.
    That is good to hear and it simplifies what I though about things somewhat, thanks. So that is the situation when the destructor is called too I am guessing.

    I am just not sure how to have id references stored by other objects preserved when one is deleted, I think I need an array of indexes in the vector and ids which are referred to. Or, if I copy the pointer instead? But does that mean if the vector removes it then it is still existing because the other object has a pointer to it stored? Also, then it would still be trying to point to a nonexistant object and errors would occur.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Objects as attributes of other objects.
    By kbro3 in forum C++ Programming
    Replies: 10
    Last Post: 08-15-2009, 03:46 PM
  2. Linked List Class with Pointers to Objects and using Polymorphism
    By CaptainMorgan in forum C++ Programming
    Replies: 3
    Last Post: 11-20-2006, 11:41 AM
  3. Replies: 60
    Last Post: 12-20-2005, 11:36 PM
  4. Question about cout an stack object?
    By joenching in forum C++ Programming
    Replies: 8
    Last Post: 05-08-2005, 10:10 PM
  5. chain of objects within pop framework help needed
    By Davey in forum C++ Programming
    Replies: 0
    Last Post: 04-15-2004, 10:01 AM

Tags for this Thread