在构造函数c ++中将指针传递给self

时间:2014-05-20 00:28:28

标签: c++ class pointers constructor

在我正在开发的基本游戏代码中,我有每个单独的区域" map"有一个单独的Area类来处理战斗和各种其他基本功能。区域中包含的每个实体都有一个指向该区域的指针,因此它可以访问区域函数和诸如此类的东西,但是该指针显然正在被删除或者某些东西正在发生,因为当它试图取消引用它时,我得到各种运行时间错误。

是不是因为我在每个NPC的构造函数中给了一个指向Area的指针?

区域构造函数

Area::Area(Game& game, std::string name, std::string id)
: GameState(game), game(game), player(game.getPlayer()), log(game, "log", 0.0f, 90.0f, 32, game.getFont("Times"), sf::Color::White)
{
    game.clearStrings();
    this->id = id;
    this->name = name;
    game.timer.restart();
    player.setArea(this);
    game.addString(DisplayString(&game, name, name + "title", game.getFont("Celt"), 10.0f, 10.0f, 64, sf::Color::White));
    //
    this->addEnemy(NPC(game, this, "Skeleton", "skel", 30, 0, 7, 10, 5, 5));
    this->addEnemy(NPC(game, this, "Skeleton", "skel", 30, 0, 7, 10, 5, 5));
    int offsetY = 0;
    for (std::map<std::string, NPC>::iterator it = enemies.begin(); it != enemies.end(); ++it)
    {
        game.addString(DisplayString(&game, it->second.getName(), it->first, game.getFont("Times"), WINDOW_WIDTH, 0, 64, sf::Color::White));
        DisplayString& name = game.getString(it->second.getID());
        game.addString(DisplayString(&game, std::to_string(it->second.hp) + " / " + std::to_string(it->second.maxhp), it->second.getID() + "hp", game.getFont("Times"), WINDOW_WIDTH, name.Text.getGlobalBounds().height, 64, sf::Color::White));

        name.setPos(WINDOW_WIDTH - name.Text.getGlobalBounds().width, offsetY);
        offsetY += name.Text.getGlobalBounds().height;

        DisplayString& hp =  game.getString(it->second.getID() + "hp");
        hp.setPos(WINDOW_WIDTH - hp.Text.getGlobalBounds().width, offsetY+name.Text.getGlobalBounds().height);
        offsetY += hp.Text.getGlobalBounds().height;
    }
}

NPC构造函数

NPC::NPC(Game& game, Area* area, std::string name, std::string id, int hp, int ap, int agil, int str, int dmg, int speed)
: game(game)
{
    this->name = name;
    this->hp = hp;
    this->maxhp = hp;
    this->ap = ap;
    this->dmg = dmg;
    this->agil = agil;
    this->str = str;
    this->speed = speed;
    this->area = area;
    this->id = id + std::to_string(game.enemyID++);
}

这是我遇到麻烦,取消引用NPC类的区域指针

void NPC::attack(Player& player)
{
    if (rand() % 100 + 1 < 5)
    {
        int damage = 2 * (this->dmg + (rand() % 6 - 3));
        player.hp -= damage;
        //any of these area pointers in the debugger show up with garbage data
        area->log.addLine(this->name + " critically strikes " + player.getName() + " for " + std::to_string(damage) + "!");
    }
    else
    {
        if (rand() % 100 + 1 > 15)
        {
            int damage = this->dmg + (rand() % 6 - 3);
            player.hp -= damage;
            area->log.addLine(this->name + " hits " + player.getName() + " for " + std::to_string(damage) + "!");
        }
        else
        {
            area->log.addLine(player.getName() + " dodges!");
        }
    }
}

请记住,从区域构造函数,NPC构造函数到攻击函数,没有任何恶作剧。区域构造函数完成,然后游戏调用区域的更新函数,该函数立即调用攻击,其间没有任何区域指针被删除或以任何其他方式修改。

我为这个令人难以置信的冗长答案道歉,并为你倾倒了一堆代码,但我对所有这些东西都很陌生,并且真的不知道该怎么做才能缩小它。如果你需要更多的代码来更好地了解正在发生的事情,我很乐意提供它,我只是在这个问题上喋喋不休地试了几天,并没有取得任何进展。< / p>

编辑:添加一些导致构建区域的代码(删除多余的代码)

void InitState::update()
{
    if(main.isOpen())
    {
        sf::Event event;
        while (main.pollEvent(event))
        {
            switch (event.type)
            {
            case sf::Event::Closed:
                main.close();
                game.Stop();
                break;
            case sf::Event::KeyReleased:
                switch (event.key.code)
                {
                    break;
                case sf::Keyboard::Key::Return:
                    switch (var)
                    {
                    case NAME:
                        if (writing)
                        {
                            game.delIcon("inputbox");
                            player.setName(game.getString("input").Text.getString());
                            game.addArea(Area(game, "The Cave", "cave"));
                            game.setState(&game.getArea("cave"));
                        }
                    default:
                        break;
                    }
                    break;
                }
                break;
        }
    }
}

InitState是一个GameState,也是一个Area。当游戏循环时,它会调用state-&gt; update()和render(),因此当游戏设置状态时,它会切换到该类的更新和渲染功能。

区域更新功能

void Area::update()
{
    if (game.getWindow().isOpen())
    {
        sf::Event event;
        while (game.getWindow().pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
            {
                game.getWindow().close();
                game.Stop();
            }
            if (event.type == sf::Event::KeyReleased)
            {
                if (event.key.code == sf::Keyboard::Key::Return)
                {
                    doCombat(); // calls attack functions for NPC and player
                }
            }
        }
    }
}

编辑编辑:更多代码! areas是一个std :: map

void Game::addArea(Area area)
{
    areas.emplace(area.getID(), area);
}

Area& Game::getArea(std::string id)
{
    return areas.find(id)->second;
}

2 个答案:

答案 0 :(得分:2)

您可以在堆栈上创建Area类的实例:

void InitState::update()

//...
game.addArea(Area(game, "The Cave", "cave"));
//...

然后你的Game :: addArea()会创建一个副本

但是你可能还没有为class Area定义一个复制构造函数,它可以处理所有的血腥细节。因此,区域对象的(自动创建的)副本可能包含指向由原始区域实例管理的对象的指针,该指针在上面的行之后被删除。

有一些不同的策略可以解决您的问题:一个简单的策略:在任何地方使用堆分配(new Area(..)而不仅仅是Area(..)),并在适用的地方使用智能指针。

您应该阅读有关C ++堆和堆栈分配,自动内存,引用,尤其是const引用等内容。

也许此链接是您的介绍:http://www.learncpp.com/cpp-tutorial/79-the-stack-and-the-heap/

编辑:顺便说一下,只要您不想或不能提供复制构造函数,标记您的对象&#34;不可复制&#34;是一种很好的风格。或者,如果您只是想要禁止它们的副本。 Non-copyable Mixin

答案 1 :(得分:0)

这只是猜测,但在调用“ player.setArea(this);之前调用” game.timer.restart(); “可能是有可能的。 “是问题所在。也许这会导致某些事情被调用,即取消引用该变量。尝试移动“player.setArea(this);”在“ game.timer.restart(); ”行之前行。或者,如果重新启动清除该变量,请将重启操作分为停止和启动操作,如下所示。

game.timer.stop();
player.setArea(this);
game.timer.start();

我希望这会有所帮助。