pighead10
pighead10

Reputation: 4305

sf::String member of class reverts to blank

These lines of code are run:

Enemy* enemy = new Enemy(m_pSceneManager,"enemy"+ss.str());
std::cout << "Enemy name = " << std::string(enemy->name) << std::endl;
Add(enemy->name,enemy);

in EnemyManager.cpp. EnemyManager inherits from GameObjectManager:

void GameObjectManager::Add(sf::String name,VisibleGameObject* obj){
    std::cout << "GameObjectManager obj name = " << std::string(obj->name) << std::endl;
    gameObjects.insert(std::pair<sf::String,VisibleGameObject*>(name,obj));
}

Enemy inherits from VisibleGameObject, which both have a public sf::String 'name' variable but only Enemy initializes it at any point (in its constructor). The output in the console window is this:

Enemy name = enemy0
GameObjectManager obj name = 

Why does the name revert to nothing? I'm assuming it's something to do with the fact that the argument is a VisibleGameObject* and not an Enemy* - if it is, how can I work around this? If I've made a mistake somewhere else, please tell me if there are any details I am missing that are required.

Thanks

Upvotes: 1

Views: 448

Answers (2)

bronekk
bronekk

Reputation: 2129

Since, as you say both have a public sf::String 'name' variable but only Enemy initializes it at any point (in its constructor). , there are two name subojects: one is a member of Enemy and another is a subobject of VisibleGameObject. Inside function Add you explicitly refer to the latter one, so that is what you get, and it is not initialised.

You probably want to make name a virtual function returning string; this will make function Add to employ runtime polymorphism and call name() from derived class, i.e. from Enemy.

Simpler (but not necessarily better) design would be to make name protected or public member of VisibleGameObject and let Enemy set it; that also means you will most likely want to remove name from Enemy, otherwise name inherited from VisibleGameObject will be hidden.

Upvotes: 1

Mankarse
Mankarse

Reputation: 40643

If I understand your description correctly, your code looks like this:

struct VisibleGameObject {
    sf::String name;
};

struct Enemy : VisibleGameObject {
    Enemy(SceneManager*, sf::String newName) : VisibleGameObject(), name(newName)
    sf::String name;
};

struct GameObjectManager {
    void GameObjectManager::Add(sf::String name,VisibleGameObject* obj){
        std::cout << "GameObjectManager obj name = " << std::string(obj->name) << std::endl;
        gameObjects.insert(std::pair<sf::String,VisibleGameObject*>(name,obj));
    }
private:
    std::map<sf::String, VisibleGameObject*> gameObjects;
};

struct EnemyManager : GameObjectManager {
    void foo() {
        //This code probably leads to a memory leak, but you might have solved it in some
        //way that you are not showing.
        Enemy* enemy = new Enemy(m_pSceneManager,"enemy"+ss.str());
        std::cout << "Enemy name = " << std::string(enemy->name) << std::endl;
        Add(enemy->name,enemy);
    }
};

What this means is - when the Enemy object is constructed, the Enemy::name variable is initialised to hold "enemy"+ss.str(). However, the VisibleGameObject::name variable (which is in the VisibleGameObject part of the Enemy) is initialised to hold its default value (in which it holds no text).

In EnemyManager::foo, the name variable that is referenced is the one in Enemy. In GameObjectManager::Add, the name variable that is referenced is the one in the VisibleGameObject base member of Enemy. VisibleGameObject::name still has its default value, and so nothing gets printed.

Upvotes: 2

Related Questions