Welcome to PlagueFest.com! Log in or Sign up to interact with the Plague Fest community.
  1. Welcome Guest! to interact with the community and gain access to all the site's features.

C++ The language of tears [Issues with virtual method overriding]

Discussion in Programming started by Luffaren, Oct 16, 2014

  1. Feb 24, 2011
    Posts
    HELP!
    I NEED SOMEBODY!
    HELP!
    NOT JUST ANYBODY!
    HELP
    YOU KNOW I NEED SOMEONE

    Here's my goal:
    I want a game with many different objects/classes.
    These classes will/should all have a update() method.
    I want to put ALL of these different classes into a single vector so i can loop through them and run the update() method.

    Here's what i've done:
    I got a Main.cpp class for running the application, where i'll update and render objects. (rendering works fine already)
    I got a Block.cpp and Block.h for game "blocks" as a basic world-building class. I want this to render and update itself.
    I got a GameObject.cpp and GameObject.h which will act as a general/parent class. It also has a static vector for updating the added objects inside the Main.cpp.
    GameObject.h has a public: virtual void update(){}
    The Block class is a child class of GameObject and has a public: void update();

    Here's my problem:
    The Block class .update() method doesn't get called from the for loop in the Main.cpp, instead the GameObject virtual update(); method gets called.
    The update method in Block doesn't override the virtual update method in GameObject.

    Class copy+paste:


    Main.cpp
    Code:
    #include <SFML/Graphics.hpp>
    #include <SFML/System.hpp>
    #include "Main.h"
    #include "Block.h"
    #include "Render.h"
    #include "GameObject.h"
    #include <iostream>
     
    int main()
    {
    	std::cout << "STARTING APPLICATION\n";
    	sf::RenderWindow window(sf::VideoMode(1024,768), "Luffaren - Game");
    	Block block;
    	GameObject &blockp = block;
    	GameObject::list.push_back(blockp);
     
    	while (window.isOpen())
    	{
    		sf::Event event;
    		while (window.pollEvent(event))
    		{
    			if (event.type == sf::Event::Closed)
    				window.close();
    		}
    		int ii = GameObject::list.size();
    		for(size_t i=0;i<ii;i++)
    		{
    			GameObject &object = GameObject::list[i];
    			object.update();
    		}
    		window.clear();
    		int jj = Render::list.size();
    		for(int j=0;j<jj;j++)
    		{
    			window.draw(Render::list[j]);
    		}
    		window.display();
    	}
    	return 0;
    }
    



    Block.cpp
    Code:
    #include "Block.h"
    #include "Render.h"
    #include <SFML/Graphics.hpp>
    #include <iostream>
     
    Block::Block()
    {
    	if(!texture.loadFromFile("Luffaren_Game_Data/Images/image.png")){}
    	sprite.setTexture(texture);
    	sprite.setPosition(10,-10);
    	sprite.setScale(1.0,1.0);
    	Render::list.push_back(sprite);
    	std::cout << "SPAWNING BLOCK\n";
    }
    void Block::update()
    {
    	sprite.setPosition(sprite.getPosition().x + 0.01 , -20);
    	std::cout << "UPDATING BLOCK CORRECTLY (from Block)\n";
    }
    



    Block.h
    Code:
    #ifndef HGUARD_Block
    #define HGUARD_Block
     
    #include <SFML/Graphics.hpp>
    #include "GameObject.h"
     
     
     
     
    class Block : public GameObject
    {
    public:
    	int X;
    	int Y;
    	Block();
    	void update();
    private:
    	sf::Sprite sprite;
    	sf::Texture texture;
    protected:
     
    };
     
    #endif
    



    GameObject.cpp
    Code:
    #include "GameObject.h"
    #include <iostream>
     
    std::vector<GameObject> GameObject::list;
     
    void GameObject::update()
    {
    	std::cout << "UPDATING BLOCK WRONGFULLY (from GameObject)\n";
    }
    



    GameObject.h
    Code:
    #ifndef HGUARD_GameObject
    #define HGUARD_GameObject
     
    #include <vector>
     
    class GameObject
    {
    public:
    	static std::vector<GameObject> list;
    	virtual void update();
    };
     
    #endif
    
    Luffaren, Oct 16, 2014 Last edited by Luffaren, Oct 17, 2014
  2. Jun 27, 2011
    Posts
  3. Feb 14, 2012
    Posts
    Try...

    static_cast<GameObject::list>(block).update();

    In place of...

    GameObject::list.update();
  4. Feb 24, 2011
    Posts
    I tried making it virtual without any results, i've also tried making the GameObject.h's update() method a non-virtual method.
    I also remembered looking at that stackoverflow link earlier today. No bigger results came out of it, alas. :frown:


    i got this: error: expected type-specifier
    Also, i want to loop through the static vector of GameObjects(children of GameObjects) and update them one by one. Wouldn't putting "block" in there only update the single Block class i added in the Main.cpp?
    I'm not entirely sure what static_cast is in itself, but shouldn't there be something different with the virtual void not being overridden?
    Thanks for your answers!
  5. Feb 14, 2012
    Posts
    Try the uppercase Block instead of block to specify the Class instead of the variable block that you made of type Block.

    NVM I see what I did I think.. try this...

    static_cast<Block>(GameObject::list).update();
    Canadian Moose, Oct 16, 2014 Last edited by Canadian Moose, Oct 16, 2014
  6. Feb 24, 2011
    Posts

    This gave me: error: no matching function for call to 'Block::Block(GameObject&)'
    :s
  7. Jun 11, 2012
    Posts
    ARGGH CRAP NOW I UNDERSTAND THE ISSUE. SHATTTTTNNEEEERRRRRRR. I knew I needed the source code.

    Try this
    Code:
    	std::cout << "STARTING APPLICATION\n";
    	sf::RenderWindow window(sf::VideoMode(1024,768), "Luffaren - Game");
    	Block block;
    	GameObject::list.push_back(&block);
    If else, try this
    Code:
    	std::cout << "STARTING APPLICATION\n";
    	sf::RenderWindow window(sf::VideoMode(1024,768), "Luffaren - Game");
    	Block block;
    	GameObject &gmOj = block
    	GameObject::list.push_back(gmOj);

    Here is my explanation.....it's odd. Technically when you use a virtual, the compiler is looking at the most derived overloaded virtual member (nothing new), however it's looking for the reference of the object not the object. So what you had was the compiler kept calling the Base::function instead of the Derived::function....In other word C+_. I can reference more explanation if I can think better now brain is buh bye. In the morning maybe.

    Also I'm skeptical because of the static member but the issue you were having where the parent Base::function was being called instead of Derived::function is the same issue where you don't use the reference of the Derived class. Here's a ideone example. http://ideone.com/aiOKRY Remove the "&" and see what it is doing. .
    A &rBase = cClass;

    Also keep it consistent. Don't declare in a cpp. Confirm if this is your GameObject.cpp?

    Code:
    #ifndef HGUARD_GameObject
    #define HGUARD_GameObject
     
    #include <vector>
     
    class GameObject
    {
    public:
    	static std::vector<GameObject> list;
    	virtual void update(){}
    };
     
    #endif
  8. Apr 9, 2007
    Posts
    Type error via
    Look into namespaces if you really want this syntax.


    You have optimized out the virtual call. Try making it a pointer to the class instead.

    Alternatively:
    PHP:
            for(size_t i=0;i<ii;i++)
            {
                
    GameObject &object GameObject::list[i];
                
    object.update();
            }
    That may not do it either. Regardless, you have serious storage issues with what you posted, so I doubt this is even compiling :koala: Time to drive home.


    EDIT: @Brian Quote Post still doesn't work very well...
  9. Feb 24, 2011
    Posts
    I updated the OP with my newest changes to the code.

    Aloha!
    I did this to my code:
    Code:
    std::cout << "STARTING APPLICATION\n";
    sf::RenderWindow window(sf::VideoMode(1024,768), "Luffaren - Game");
    Block block;
    GameObject &gmOj = block
    GameObject::list.push_back(gmOj);
    
    I tried that ideone link and it gave me some good insight about virtual overriding.
    From what i got out of this is..
    Calling the method on the object = the parent method gets called.
    Calling the method on the pointer pointing to the object = the object method gets called, overriding the initial parent method.
    Correct me if i am el wrongo.

    I tried various combinations, including making "GameObject &gmOj = block" into "Block &gmOj = block" without any results, it still calls the parent method.
    And again, calling the object or gmOj (which i named blockp "blockpointer") MANUALLY calls the update method correctly for the specific object. But i need this to work/be done through the for loop.

    And in regards of the for loop, @Kyle

    for(size_t i=0;i<ii;i++)
    {
    GameObject &object = GameObject::list[i];
    object.update();
    }

    I implemented this with no other result, it still calls the parent virtual method. :frown:
    I am going numb in my head and left pinky toe, what is wrong with my thing?
    Luffaren, Oct 17, 2014 Last edited by Luffaren, Oct 17, 2014
  10. Feb 24, 2011
    Posts
    The issue at hand has been solved!

    Kyle and i had a pm-rundown on the problem, and it seems like i've been a bad coder all along.

    Changes made that fixed it:
    - Set the vector into a pointer-vector
    - Make a pointer out of the object and add that instead of the object
    - De-referencing the pointer in the for loop and then calling the .update() method
    Code:
    ------ Main.cpp ------
    GameObject * block = new Block();
    GameObject::list.push_back(block);
     
    int ii = GameObject::list.size();
    for(size_t i=0;i<ii;i++)
    {
    	GameObject *object = GameObject::list[i];
    	(*object).update();
    }
     
    ------ GameObject.cpp ------
    std::vector<GameObject*> GameObject::list;
     
    ------ GameObject.h ------
    static std::vector<GameObject*> list;
    
    I have to thank Bender a whole lot for having the patience dealing with a whiny, crying Swede. As for doing lots of error-searching and tests.
    Also thanks for all your answers in this thread, now i don't have to cry myself to sleep tonight.
    /xoxo yours truly - L00f
    • Informative Informative x 1