如何使用 OOP 运行存储在容器中的实际对象的函数?

2024-04-17

如何使用 OOP 运行存储在容器中的实际对象的函数?

背景:我正在编写一个游戏。有 4 间相连的房间。有两种不同的房间类型和两种不同的玩家类型。玩家应该作为线程运行。杀手应该在行动室中与普通玩家进行战斗。在第二种类型的房间里,不应该发生任何事情。简化了游戏逻辑和代码。

当线程启动时,void Player::operator()()正在被执行。玩家进入房间,执行他的行动initializeAction(),然后离开它。如果发生杀手,他的initializeAction()导致room->actionInRoom(*this),它执行player.inActionRoom().

问题出在这段代码中void Killer::inActionRoom():

std::vector<Player> &playersWithoutKillers = room->getPlayersWithoutKillers();
auto it = playersWithoutKillers.begin();
std::advance(it, 0);
Player chosenPlayerForFight = *it;
...
chosenPlayerForFight.decreasePoints();

where chosenPlayerForFight.decreasePoints();不会减少实际玩家的分数,但我认为它会减少对象的副本。

如果我运行代码,这个错误是可见的:OtherPlayer 的点数将始终重置为 1。如果我每次战斗发生时都减少它,则预期会出现负值。

-> Killer in Forth room Killer 11 vs OtherPlayer 1
Starting decreasing points from 1
Ending decreasing points from 0

我尝试修复代码,主要是通过确保传递对象的引用。

主要.cpp:

#include <iostream>
#include <memory>
#include <thread>
#include "Room.h"
#include "Player.h"

std::mutex globalMessageMutex;

int main() {

    auto first = std::make_shared<RelaxRoom>("First room");
    auto second = std::make_shared<ActionRoom>("Second room");
    auto third = std::make_shared<RelaxRoom>("Third room");
    auto forth = std::make_shared<ActionRoom>("Forth room");

    first->setRoomPair(second, forth);
    second->setRoomPair(third, first);
    third->setRoomPair(forth, second);
    forth->setRoomPair(first, third);

    std::vector<std::thread> players;

    players.emplace_back(OtherPlayer("OtherPlayer", first));
    players.emplace_back(Killer("Killer", first));

    for (auto &t : players) {
        if (t.joinable()) {
            t.join();
        }
    }

    return 0;
}

Player.h

#ifndef HW03_PLAYER_H
#define HW03_PLAYER_H

#include <string>
#include <memory>

class Room;

class Player {
    friend class Room;
public:
    Player(const std::string &playerName, std::shared_ptr<Room> initialTargetRoom);
    void operator()();
    friend bool operator== ( const Player &lhs, const Player &rhs );
    const std::string &getName() const;
    virtual void inActionRoom() {};
    virtual void inRelaxRoom(Room &pRoom) {};
    virtual bool isKiller()const;
    virtual bool isOtherPlayer();
    int getPoints()const;
    void increasePoints();
    void decreasePoints();
    int points;
protected:
    std::shared_ptr<Room> room;
    virtual void initializeAction();
private:
    std::string name;
    std::shared_ptr<Room> initialRoom;
};

class OtherPlayer : public Player {
public:
    OtherPlayer(const std::string &playerName, const std::shared_ptr<Room> &initialTargetRoom);
    void initializeAction() override;
    void inActionRoom() override;
    void inRelaxRoom(Room &pRoom) override;
    bool isOtherPlayer() override;
};


class Killer : public Player {
public:
    Killer(const std::string &playerName, const std::shared_ptr<Room> &initialTargetRoom);
    void initializeAction()  override;
    void inActionRoom() override;
    void inRelaxRoom(Room &pRoom) override;
    bool isKiller() const override;
};


#endif //HW03_PLAYER_H

播放器.cpp

#include <iostream>
#include <chrono>
#include <thread>
#include <random>
#include "Player.h"
#include "Room.h"

extern std::mutex globalMessageMutex;

Player::Player(const std::string &playerName, std::shared_ptr<Room> initialTargetRoom) {
    name = playerName;
    initialRoom = initialTargetRoom;
    room = initialTargetRoom;
    points = 1;
}

void Player::operator()() {
    room->enter(*this);
    initializeAction();
    std::this_thread::sleep_for(std::chrono::milliseconds(20));
    room->leave(*this);

    while (auto nextRoom = room->getNext()) {
        room = nextRoom;
        nextRoom->enter(*this);
        initializeAction();
        std::this_thread::sleep_for(std::chrono::milliseconds(20));
        nextRoom->leave(*this);
    }
}

void Player::initializeAction() {}

bool operator==(const Player &lhs, const Player &rhs) {
    return lhs.name == rhs.name;
}

const std::string &Player::getName() const {
    return name;
}

bool Player::isKiller() const {
    return false;
}

bool Player::isOtherPlayer() {
    return false;
}

int Player::getPoints() const {
    return points;
}

void Player::increasePoints() {
    points++;
}

void Player::decreasePoints() {
    std::cout << "Starting decreasing points from " << points << std::endl;
    points--;
    std::cout << "Ending decreasing points from " << points << std::endl;
}


OtherPlayer::OtherPlayer(const std::string &playerName, const std::shared_ptr<Room> &initialTargetRoom) : Player(playerName,
                                                                                                         initialTargetRoom) {}

void OtherPlayer::initializeAction() {
    room->actionInRoom(*this);
}

void OtherPlayer::inActionRoom() {}

void OtherPlayer::inRelaxRoom(Room &pRoom) {}

bool OtherPlayer::isOtherPlayer() {
    return true;
}


Killer::Killer(const std::string &playerName, const std::shared_ptr<Room> &initialTargetRoom) : Player(playerName,
                                                                                                         initialTargetRoom) {}

void Killer::initializeAction() {
    room->actionInRoom(*this);
}

void Killer::inActionRoom() {
    std::lock_guard<std::mutex> ml(globalMessageMutex);
    if (!room->getPlayersWithoutKillers().empty()) {

        **std::vector<Player> &playersWithoutKillers = room->getPlayersWithoutKillers();**

        **auto it = playersWithoutKillers.begin();
        std::advance(it, 0);
        Player chosenPlayerForFight = *it;**

        auto killersVitality = this->getPoints();
        auto othersPlayerPoints = chosenPlayerForFight.getPoints();

        std::cout << "-> Killer in " << room->getName() << " " << this->getName() << " " << killersVitality
                  << " vs " << chosenPlayerForFight.getName() << " " << othersPlayerPoints << std::endl;

        this->increasePoints();
        **chosenPlayerForFight.decreasePoints();**
    }
}

void Killer::inRelaxRoom(Room &pRoom) {

}

bool Killer::isKiller() const {
    return true;
}

Room.h

#ifndef HW03_ROOM_H
#define HW03_ROOM_H

#include <string>
#include <vector>
#include <condition_variable>


class Player;
class Room {

public:
    Room(const std::string &roomName);
    void setRoomPair(std::shared_ptr<Room> firstRoom, std::shared_ptr<Room> secondRoom);
    std::shared_ptr<Room> getNext();
    void enter(Player &player);
    void leave(Player &player);
    virtual void actionInRoom(Player &player)= 0;
    const std::string &getName() const;
    const std::vector<Player> &getPlayers();
    std::vector<Player> &getPlayersWithoutKillers();

protected:
    std::string name;
    size_t killersCount;
    size_t playersWithoutKillersCount;

private:
    std::vector<Player> players;
    std::vector<Player> playersWithoutKillers;
    std::condition_variable cv;
    std::mutex mutex;
    std::pair<std::shared_ptr<Room>, std::shared_ptr<Room>> roomPair;
    void updateCounterPlayerLeaves(Player &player);
    void updateCounterPlayerEnters(Player &player);
};

class ActionRoom : public Room {
public:
    ActionRoom(const std::string &roomName) : Room(roomName) {}
    void actionInRoom(Player &player) override;
};

class RelaxRoom : public Room {
public:
    RelaxRoom(const std::string &roomName) : Room(roomName) {}
    void actionInRoom(Player &player) override;
};

#endif //HW03_ROOM_H

Room.cpp

#include <iostream>
#include <algorithm>
#include <random>
#include "Room.h"
#include "Player.h"
#include <mutex>

extern std::mutex globalMessageMutex;


Room::Room(const std::string &roomName) {
    name = roomName;
}

const std::string &Room::getName() const {
    return name;
}

std::shared_ptr<Room> Room::getNext() {
    auto seed = std::chrono::high_resolution_clock::now().time_since_epoch().count();
    std::mt19937 engine(seed);
    std::uniform_int_distribution<int> randomGenerator(0, 1);
    auto randomNumber = randomGenerator(engine);
    if (randomNumber) {
        return roomPair.second;
    }
    return roomPair.first;
}

void Room::enter(Player &player) {
    std::unique_lock<std::mutex> lock(mutex);

    cv.wait(lock, [this, &player] {
                return true;
            }
    );

    players.push_back(player);

    updateCounterPlayerEnters(player);

    std::lock_guard<std::mutex> ml(globalMessageMutex);
    std::cout << name << ": killers: " << killersCount << ", other players: " << playersWithoutKillersCount <<
              std::endl;
}

void Room::updateCounterPlayerEnters(Player &player) {
    if (player.isKiller()) {
        killersCount++;
    } else {
        playersWithoutKillersCount++;
        playersWithoutKillers.push_back(player);
    }
}

void Room::leave(Player &player) {
    {
        std::lock_guard<std::mutex> lock(mutex);
        auto it = std::find(players.begin(), players.end(), player);
        if (it == players.end()) {
            return;
        }
        players.erase(it);

        updateCounterPlayerLeaves(player);
    }

    cv.notify_all();
}

void Room::updateCounterPlayerLeaves(Player &player) {
    if (player.isKiller()) {
        killersCount--;
    } else {
        playersWithoutKillersCount--;
        auto it = std::find(playersWithoutKillers.begin(), playersWithoutKillers.end(), player);
        if (it == playersWithoutKillers.end()) {
            return;
        }
        playersWithoutKillers.erase(it);
    }
}

void Room::setRoomPair(std::shared_ptr<Room> firstRoom, std::shared_ptr<Room> secondRoom) {
    roomPair.first = std::move(firstRoom);
    roomPair.second = std::move(secondRoom);
}

const std::vector<Player> &Room::getPlayers() {
    return players;
}

std::vector<Player> &Room::getPlayersWithoutKillers() {
    return playersWithoutKillers;
}

void ActionRoom::actionInRoom(Player &player) {
    player.inActionRoom();
}

void RelaxRoom::actionInRoom(Player &player) {
    player.inRelaxRoom(*this);
}

不是一个完整的答案,因为你说这是一项家庭作业。

但是,可以用来解决此问题的一种模式是让容器存储std::unique_ptr<some_base_class>值,或者如果需要的话std::shared_ptr<some_base_class>,并用指向派生对象的指针填充它们。例如:container.emplace_back(static_cast<some_base_class*>(new derived_class(foo, bar, baz)));将在容器内构建所有内容,因此编译器不需要制作任何临时副本。你也可以写一些类似的东西:

std::vector<std::unique_ptr<some_base_class>> container;

{
   std::unique_ptr<derived_class> temp =
     make_unique<derived_class>();
   temp->setup( foo, bar, baz );
   container.emplace_back(static_cast<some_base_class*>(temp.release()));
   // temp is now empty, and the pointer in the container now owns the object.
}

您可以使用完整的界面some_base_class通过这些智能指针,->,但如果您需要将它们转回对派生对象的引用,则可以使用 RTTI 和dynamic_cast.

还有其他方法,包括受歧视的工会和std::variant,但我建议您在这里尝试存储指向定义接口的基类的智能指针。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 OOP 运行存储在容器中的实际对象的函数? 的相关文章

随机推荐

  • 使用 Actionscript 3 连接到数据库 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我正在寻找有关如何基于数据库在 Flash 中动态创建内容的建议 最初我想将数据库导出到 XML 文件并使用内置的 Actionscr
  • 如何在 Maven 3 站点插件中禁用测试 Javadoc 报告的生成?

    这是我的pom xml 我正在尝试禁用Test Javadoc报到site
  • 如何修复 VS Code 中的错误文件描述符错误?

    我有 vsc 版本 1 63 2 我收到以下通知 文件更改观察程序意外停止 重新加载窗口可能会再次启用观察程序 除非无法监视工作区的文件更改 在 窗口 日志 使用命令面板中的 开发人员 打开日志文件 命令打开 中 出现错误 renderer
  • 使用 R 中的传单库绘制跨越国际日期变更线的路线

    我有兴趣使用 R 的传单库绘制从滑铁卢到台湾的路线 路线的坐标是使用 geosphere 中的 gcIntermediate 函数获得的 然而 该路线涉及穿越国际日期变更线 因此该路线在地图边缘被切断 并在顶部与直线连接 我得到的情节 错误
  • JUnit 5 何时提供场景测试?

    在一次会议 JavaForum Stuttgart 2016 上 他们表示 JUnit 5 将包含一个支持场景测试的功能 http 2016 java forum stuttgart de de Abstracts Slot 1 html
  • Keras LSTM 输入形状的输入形状错误

    在 Keras 中使用时间序列时出现此错误 ValueError Error when checking input expected lstm 1 input to have 3 dimensions but got array with
  • Swift 中基于内容的动态 UITextView 大小

    我不认为有人可以指导我在仍然使用自动布局的同时动态调整 UITextView 大小的正确方法 使用 Swift 就是这样 我尝试以编程方式调整底部约束 试图让 UITextView 拥抱内容 但我不知道如何获取 UITextView 内容的
  • TinyMCE 在 DOM 中渲染后执行操作

    我正在使用 TinyMCE 4 并按如下方式设置 tinyMCE init mode specific textareas editor selector basicTinyMCE theme modern readonly false 我
  • 长度为 5 的回文数

    给定一个二进制字符串 S 找到长度为 5 的回文子序列的数量 长度为 5 的回文子序列是数组 a 我的想法 我想出了如下的递归 palin s palin s 1 palin s 1 palin s 1 1 当 s 0 s 1 时 就是上面
  • Tomcat:绕过指定 IP 地址的基本身份验证

    我已经配置 tomcat 进行基本身份验证 我不希望任何人访问我的 Web 应用程序 但该应用程序正在提供 Web 服务 所以我想从基本身份验证中绕过特定的IP地址 该IP不应该需要身份验证 tomcat users xml
  • Tomcat 8.5.29 HTTP/2 不支持 GZIP 压缩

    我正在使用 Tomcat 8 5 29 并使用相应的配置 我已为该站点启用了 HTTP2 支持 以下是 server xml 文件中的配置
  • set_index 不在 pandas 中建立索引

    对于下面的简单程序 我期望第二个输出与第一个输出相同 为什么这没有发生 这只是订单的改变data1 and data2 columnList PID Sec Util random data1 67123 12 85 100 67123 1
  • 以编程方式关闭 USB 端口的电源

    我正在开发一个项目 我想使用这些 http www woot com blog post usb powered woot off lights 2 http www woot com blog post usb powered woot
  • git 克隆失败并显示“ssh_dispatch_run_fatal”

    我已经配置了ssh密钥 但仍然无法成功git克隆 错误信息是 git clone email protected cdn cgi l email protection alimail frontend ragusa git Cloning
  • 使用 VBA 实现简单的替换密码

    我正在尝试编写一个程序来更改字符串中的字母 但我一直遇到一个明显的问题 即如果它更改了值 例如将 A 更改为 M 当它更改为 M 时 它会将 M 更改为其他值 因此 当我运行代码将其全部更改回来时 它会将其转换为好像该字母最初是 M 而不是
  • CommandError:使用 Flask-Migrate 迁移时无法找到由“...”标识的修订版本

    我今天开始使用 Flask Migrate 并将其安装在一个测试项目上 但是我收到以下错误 alembic util exc CommandError 无法找到由 e39d16e62810 重现步骤 运行 python create db
  • 如何避免子文件夹上的 svn:mergeinfos ?

    我们尝试仅将 svn mergeinfo 属性保留在根分支文件夹上 然而 我们不断看到它渗入子文件夹中 我们已经能够确定一些可能的原因 在存储库浏览器中移动文件夹 在 IntelliJ 中移动和 或重命名包 使用旧的 svn 客户端 任何人
  • 在azure devOps中,如何在项目中复制仪表板

    我在项目中创建了一个仪表板 并插入小部件来显示团队进度 目前 仪表板中有 2 个团队 每个团队有 8 个小部件 我想将它们分开 以便每个团队都有自己的个人仪表板 因为我不想真正从头开始制作它 所以我想复制它 然后删除其他团队在每个新的个人仪
  • FASM 是否使用 Intel 语法?

    我尝试在 FASM 中编译以下代码 mov DWORD PTR ebp 4 1234567 它给了我一个 无效表达式 错误 但是以下代码有效 mov DWORD ebp 4 1234567 那么 FASM 是否使用 Intel 语法 我假设
  • 如何使用 OOP 运行存储在容器中的实际对象的函数?

    如何使用 OOP 运行存储在容器中的实际对象的函数 背景 我正在编写一个游戏 有 4 间相连的房间 有两种不同的房间类型和两种不同的玩家类型 玩家应该作为线程运行 杀手应该在行动室中与普通玩家进行战斗 在第二种类型的房间里 不应该发生任何事