【问题标题】:C++ Derived classes cannot modify a base class' attributes but an external class canC++ 派生类不能修改基类的属性,但外部类可以
【发布时间】:2020-05-24 13:29:39
【问题描述】:

我正在做一个扑克引擎,以便不同的 PokerPlayer 代理可以在锦标赛模拟中相互对战。一旦我的项目完成,我希望人们在 PR 中提交他们自己的代理。为此,他们只需使用 MyPokerPlayer 类派生 PokerPlayer 类并覆盖 play() 方法。但我想确保他们的经纪人不会作弊。我不希望他们能够改变他们拥有的钱,也不希望他们能够改变他们在游戏开始时得到的卡片。

问题是 Game 类需要能够在 PokerPlayer 下注时拿走他们的钱(或者在他们获胜时给他们底池)并且需要能够在游戏开始时设置 PokerPlayer 的牌。所以PokerPlayer的派生类不能直接更新自己的钱和牌,但外部类Game可以。

PokerPlayer.h(这是应该由代理派生的类)

class PokerPlayer
{
private:
    bool alive = true;
    QList<Card> cards;
    int money;

public:
    PokerPlayer();
    int getMoney() const;
    bool isAlive() const;
    virtual Action* play() = 0;
};

Game.cpp(我在其中为玩家分配牌、下注等...)

...
void Game::assignCardsToEveryPlayer() {
    foreach (PokerPlayer* player, this->getPlayers()) {
        QSet<Card> cards = PokerGameManager::generateUniqueCards(2);
        player->setCards(cards.toList());
    }
}
...

我不想要的: MYPokerPlayer.cpp(代理)

Action* MYPokerPlayer::play() override {
    this->setMoney(1000000);
    this->setCards(ACE, ACE);
    // you get the idea...
}

我怎样才能做到这一点?

感谢您的宝贵时间,

【问题讨论】:

  • 欢迎使用 stackoverflow,发布您拥有的代码,或者更好的是 minimal, reproducible example
  • 感谢您的评论@anastaciu。我在我的代码中添加了示例,我认为这些示例说明了我在说什么

标签: c++ oop friend derived-class


【解决方案1】:

您可以将不应被欺骗的金钱和其他值存储为基类的私有成员,并将它们的更改限制为仅 PokerPlayer 的私有函数,这些函数应该由游戏调用或任何应该能够更改的函数:

class Game;

class PokerPlayer {
  friend class Game;
private:
  int money;
public:
  int getMoney() const;
};

【讨论】:

  • 这种方法很容易破解/绕过/破解,而且在任何方面都不安全。
  • 非常感谢@passing_through。我知道 friend,但作为 C++ 初学者,我的印象是使用 friend 是糟糕设计的标志。在这种情况下,可能很容易通过强制转换来绕过
【解决方案2】:

让我们回顾一下您的课程背后的概念。 PokerPlayer 是参与者之一。这个玩家负责追踪它是否还活着,它有哪些卡片,以及它有多少钱。这听起来像是对不允许作弊的游戏的准确模拟吗?

没有?为什么不?一方面,庄家/庄家决定谁拿到哪张牌。玩家可以查看卡片但不能更改它们。所以你的课应该是相似的。 (金钱是一个值得分析的有趣方面,因为真正的玩家可能会带一张 ATM 卡……;))玩家购买筹码,坐下,然后行动。其他一切都由房子控制(或至少监督)。玩家带来的只是起步资金和大脑(即如何play())。

让我们看看我们能否更准确地为扑克游戏建模。有一群人围坐在一张桌子旁。 桌子上有许多牌,其中一些牌可以被某些玩家查看。所以......也许你所谓的“玩家”在你拿走play方法之后应该更准确地被视为“椅子”。桌子拥有椅子,给每张椅子卡片,并处理将扑克筹码移入/移出椅子(从/移到底池)。

每个玩家都可以简化为桌面视图(用于下注、弃牌等)、const 椅子视图(用于查看他们的牌和状态),以及虚拟的play方法。玩家通过从table 购买筹码加入游戏,然后table 为他们分配chairplayer只能通过table提供的方法影响游戏。


诚然,作弊仍然是可能的(例如,从chair 中丢弃const)。 C++ 语言与源代码中的安全性无关。存在的护栏是为了防止意外侵权;他们不会阻止其他人在同一程序上的恶意。不过,您可以引入一定程度的间接性以使事情更加安全。供玩家查看的chair 可能是table 维护的chair 的副本。恶意程序员操纵他们的椅子副本不会改变 table 跟踪的内容。

【讨论】:

  • 谢谢@JaMit!所以,基本上, PokerPlayer 类只会存在,以便它的 play() 方法可以被覆盖,并且代理(派生类)将使用 Game (或您的示例中的表)提供的 API 来访问他们的牌,知道他们多少钱有,等等……
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-12-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-10
相关资源
最近更新 更多