【问题标题】:Stack returning copy because of inheritance?由于继承而堆栈返回副本?
【发布时间】:2016-08-28 03:06:27
【问题描述】:

我在尝试让我的堆栈容器适配器通过引用从 getter 返回时遇到了一些麻烦。每次我尝试对它做一个吸气剂时,即使使用引用运算符,它似乎也在制作它的副本。我这样说是因为每当我在一个类中调试和观察容器时,容器的大小就像预期的那样是 1,因为我将一个对象推入堆栈。但是,一旦我通过函数进入另一个类...该类将堆栈的大小更改回 0。直到我返回调用该函数的内容,然后它才返回 1。

是不是因为我继承自使用容器的类?接下来是我的下一个问题......继承是复制母类中的成员还是引用它们?我将尝试用最少的代码来解释这一点,所以请客气...

GAME.HPP

#ifndef GAME_HPP
#define GAME_HPP

#include <stack>
#include "GameState.hpp"

class Game
{
public: 
    Game();
    ~Game();

    int playGame();

protected:
    std::stack<GameState*>& getGStates();

private:
    std::stack<GameState*> gameStates; //GameState is a abstract class (no implementation)
    bool gameRunning;
};

#endif

GAME.CPP

int Game::playGame()
{
    gameRunning = true;

    SplashScreen sScreen; // SplashScreen inherits from GameState class
    gameStates.push(std::move(&sScreen)); //move screen to stack without making a copy

    // The stack size is now 1

    while (gameRunning)
    {
        gameStates.top()->runState();
    }
        return 0;
}

std::stack<GameState*>& Game::getGStates()
{
    return gameStates; //returns stack
}

GAMESTATE.HPP

#ifndef GAMESTATE_HPP
#define GAMESTATE_HPP

class GameState
{
public:
    GameState(){};
    ~GameState(){};

    virtual void runState() = 0;
    virtual void resumeState() = 0;
    virtual void pauseState() = 0;
    virtual void update() = 0;
    virtual void render() = 0;
};
#endif

我确实在SplashScreen 类中提供了大量的实现,但如果我删除它,问题仍然存在。所以现在为了简单起见,我只想说它和你在GameState 标题中看到的没有什么不同,但是有空白块和返回。我仍将显示runState() 位,但将其简化以限定问题范围。

SPLASHSCREEN.CPP

//obvious header includes above

void SplashScreen::runState()
{
    std::cout << getGStates() << std::endl; //here the stack is 0
    std::cin.get(); //getting char from input stream so program won't terminate so fast
    return; //here I return to what invoke the runState() but stack becomes 1 again in the other class...Is a copy being returned by the getter ??
}

我想提一提的是SplashScreen 类确实继承自GameStateGame 类。我从GameState 类继承,所以我可以将它用作我的SplashScreen 类的接口,我从Game 类继承,所以我可以使用getter 方法。

您可能会说为什么我不通过Game.cpp 中的函数runState() 直接通过引用传递。我可以并且它会起作用,但是有没有另一种方法可以做到这一点而不会使我的函数与参数混淆?我不想每次我需要一些东西时都添加一个参数。再说一次,如果我这样做,我的对象设计很差,对吗?请帮忙...

【问题讨论】:

  • SplashScreen sScreen; gameStates.push(std::move(&amp;sScreen)); - 不,不,不!这不是管理内存的安全方法。
  • @user2357112 请用您的知识启发我...什么是更好的方法? .:(∩´ ﹏ `∩):.
  • SplashScreen 的定义范围一结束就会自毁。您需要动态分配它,可能使用new,或者重组您的程序,使其不必使用new。为什么SplashScreen 继承自Game?闪屏不是游戏。听起来你还没有理解继承到底是什么
  • 该初始屏幕有自己的GameState 指针堆栈。您正在调用初始屏幕的 getGStates 方法,而不是您需要访问的对象的方法。启动画面甚至无法知道您想要的 Game 对象的 getGStates 方法。
  • @user2357112 哦哦,我之所以让SplashScreen 从游戏继承,是因为我将SplashScreen 视为游戏的一部分,你知道它是第一个屏幕。我还读到 GameStates 就像您游戏中的单独程序/游戏,这就是我这样做的原因。我想我读的那篇文章不好吧?另外,我知道SplashScreen 将在结束块处终止,但playGame 实际上是我的结束块。我的程序运行来自其他状态类的状态,当游戏结束时它返回到playGame,然后终止循环。

标签: c++ c++11 inheritance


【解决方案1】:

您提到SplashScreen 继承自Game。 因此,如下代码:

void SplashScreen::runState()
{
    std::cout << getGStates() << std::endl; //here the stack is 0
    std::cin.get(); //getting char from input stream so program won't terminate so fast
    return; //here I return to what invoke the runState() but stack becomes 1 again in the other class...Is a copy being returned by the getter ??
}

打印Splashscreen 实例对象的堆栈,而不是初始Game 实例对象。换句话说,您打印的堆栈与您将SplashScreen 对象推送到的堆栈不同,甚至不是其副本,而是完全不相关的GameState 堆栈。

您的问题是:继承不是推理GameSplashScreen 之间关系的正确方法。继承主要是模型类之间的“是一种”关系,看起来 SplashScreen 可能不是一种游戏。您要表示的关系类型是使用关系,通过引用您将要使用的对象或将其作为参数传递到调用堆栈中的某处来表示。

如果您需要访问游戏,您可能应该:

  1. 将其作为成员变量添加到您的 SplashScreen 类中,例如

    //Splashscreen.h
    class SplashScreen : public GameState {
        public:
        SplashScreen(Game& game)
        : m_game(game) {
        }
    
        ...    
    
        private:
        Game& m_game;
    }
    
    //SplashScreen.cpp
    void SplashScreen::runState()
    {
        std::cout << m_game.getGStates() << std::endl; //here the stack is 0
        std::cin.get(); //getting char from input stream so program won't terminate so fast
        return; //here I return to what invoke the runState() but stack becomes 1 again in the other class...Is a copy being returned by the getter ??
    }
    
  2. 或将其作为参数传递给您的 runState 方法,例如

    void SplashScreen::runState(Game& game)
    {
        std::cout << game.getGStates() << std::endl; //here the stack is 0
        std::cin.get(); //getting char from input stream so program won't terminate so fast
        return; //here I return to what invoke the runState() but stack becomes 1 again in the other class...Is a copy being returned by the getter ??
    }
    

【讨论】:

  • 好吧,比如说我在 main 中声明了我的游戏对象,并像 game.playGame() 一样调用了 playGame()。你上面说的还是引用同一个游戏对象?
  • 没关系,我想通了。我从mainGame 引用参数传递给我的playGame() 函数。在Game 中编辑了我的playGame() 函数签名,这样我就可以将Game 的引用传递到我需要的任何地方。非常感谢!
猜你喜欢
  • 1970-01-01
  • 2012-03-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-25
相关资源
最近更新 更多