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

标签 c++ class pointers constructor

在我正在开发的基本游戏代码中,“ map ”的每个单独区域都有一个单独的 Area 类,用于处理战斗和各种其他基本功能。 Area 中包含的每个实体都有一个指向该 Area 的指针,因此它可以访问 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!");
        }
    }
}

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

我为这个令人难以置信的冗长答案和向你倾倒一堆代码表示歉意,但我对所有这些东西都是新手,真的不知道要剪掉什么来压缩它。如果您需要更多代码来更好地了解正在发生的事情,我很乐意提供它,我已经为此绞尽脑汁好几天了,试图解决它,但没有取得任何进展。

编辑:添加一些导致区域构造的代码(删除无关代码)

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 也是一个 GameState。当游戏循环时,它会调用 state->update() 和 render(),因此当游戏设置状态时,它会切换到该类的 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
                }
            }
        }
    }
}

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

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

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

最佳答案

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

void InitState::update()中:

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

然后您的 Game::addArea() 创建它的拷贝

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

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

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

也许这个链接是给你的介绍:http://www.learncpp.com/cpp-tutorial/79-the-stack-and-the-heap/

编辑:顺便说一句,每当您不想或无法提供复制构造函数时,将对象标记为“不可复制”是一种很好的风格。或者如果您只是想禁止它们的拷贝。 Non-copyable Mixin

关于c++ - 在构造函数 C++ 中将指针传递给 self,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23749209/

相关文章:

返回自定义类数组的 c++ 函数会出错

C++ 函数说明

html - 当我可以使用自己的标签时,为什么要使用 "class="?

c++ - 将现有的 C++ 对象传递给 Lua

c - 我们如何使用指向数组的指针访问二维数组的内容

c++ - 从命令行向 C++ 传递参数

c++ - 如何访问 C++ 中的 cli 类?

c++ - 元组实现是否有优化的布局?

javascript - 如果语言后缀不存在,则将其添加到 url (javascript)

c - 函数中的指针问题