【问题标题】:Two objects that need to reference each other. Bad Idea?需要相互引用的两个对象。馊主意?
【发布时间】:2016-02-16 05:55:00
【问题描述】:

我正在用 C++ 开发一个非常小而简单的游戏引擎。我有一个生物类和一个武器类。生物需要知道它拥有什么武器,每个武器都需要知道拥有它的生物。我想让武器知道它有什么生物的主要原因是防止它摧毁自己的生物(当武器攻击时,会检测到它碰撞的所有生物并杀死它们,除了拥有武器的生物)。

这是(简化的)Creature 类的样子:

class Creature {
    private:
    Weapon* weapon_;
    public:
    void SetWeapon(Weapon* w){
        // do some other stuff (e.g. remove Weapon from any other Creatures)
        weapon_ = w;
        w->creature_ = this;
    }
}

这是(简化的)Weapon 类的样子:

class Weapon{
    friend class Creature; // Creature needs access to creature_ pointer
    private:
    creature_;
}

如你所见,我将 Creature 设置为 Weapon 的友元类,以便 Creature 的 setWeapon() 方法可以适当地设置私有的 creative_ 指针。

我的具体问题:

  1. 我听说两个对象相互引用是糟糕的设计。但就我而言,我怎么会不这样做呢?我真的“感觉”每个生物都应该知道它拥有什么武器,每个武器都应该知道它拥有什么武器(这样它就不会伤害那个生物)。有没有什么方法可以在不让这两个类相互引用的情况下实现我想要的?我在使用地图/实体、库存/物品等的游戏引擎中一遍又一遍地遇到同样的问题......似乎每当我有一个“容器”类和一个“项目”类时,这个引用问题就会再次出现。我只想将添加项目的责任放在其中一个类中,但我希望两个类相互了解(即我希望生物知道它的武器,武器知道它的生物)。有没有办法在不让两个项目相互引用的情况下实现这一点?

  2. 这种设计有时是必要的吗?或者有没有一种通用的方法来避免它同时实现相同类型的功能?

  3. 如果这种设计对于实现此类功能确实是必要的,那么使用友元类是处理它的正确方法吗?

提前非常感谢您。我非常有兴趣了解是否有一种方法可以在不让对象相互引用的情况下实现此类功能。

【问题讨论】:

  • 你有没有考虑过让生物攻击而不是武器?然后你可以有一个知道武器和生物的attack()方法,因为生物有武器并且生物知道自己。
  • @Knox 我确实考虑过这一点,但是我希望攻击行为在于武器,而不是生物。当一个生物被告知要攻击()时,它应该简单地委托给武器_.攻击()。这将允许生物动态交换武器。
  • 然后也许让生物的attack()方法调用武器的_attack(Entity),这样你就可以为武器范围内的每个实体(不包括它自己)调用_attack()。
  • 这在某些情况下是个好主意,但是,这会使诸如“飞溅”伤害之类的事情变得更加困难。 attack() 当前的工作方式是,它播放动画并检查与精灵的碰撞。即使我有武器的 attack() 方法将实体作为参数,我仍然会遇到同样的检查问题,以确保拥有的实体没有被破坏。在我的情况下,这种双重引用似乎确实是必要的。不过谢谢!

标签: c++ dependencies friend


【解决方案1】:

此类问题时有发生,可通过以下技术解决:

class Creature {
public:
    void SetWeapon(Weapon* w) {
        weapon_ = w;
        weapon_->SetCreature(this);
    }
private:
    Weapon* weapon_;
};

class Weapon {
public:
    void SetCreature(Creature* _creature) {
        m_owner = _creature;
    }
private:
    Creature* m_owner;
};

关于您的广泛问题 - 如果您在同一个项目中经常遇到此类问题,我建议您重新考虑您的设计解决方案。
例如,您关于武器知道它是生物的提议是违反直觉的,并且不感觉不对所以从这个假设开始,我相信你最终会得到更好的设计,你的武器不会知道他们的主人(就像在现实生活中一样!)。

【讨论】:

  • 很好的解决方案,但问题是现在我无法更改武器所属的生物。我可能应该在我的问题中提到,我会继续更新它。谢谢!
  • @MeLikeyCode 如果您将Creature& _owner 更改为Creature * _owner,您会这样做
  • 这意味着 Weapon::SetCreature() 函数必须是公开的。这会给客户一个调用它的机会,这不是我想要的。这样做的原因是因为在将武器设置为生物之前,我想做一些其他的事情。我不希望客户能够调用公共函数来绕过它。不过谢谢!
【解决方案2】:
  1. 你没听错。以这种方式使用引用对象不是一个好的编程习惯,但是再次使用goto 也被某些人认为是一种不好的方法。有关替代解决方案,请参见下文。

  2. 这种设计可以用于有时我们需要goto 循环。但是很多人不喜欢这种方法。

替代解决方案: 根据您的要求,我可以建议一种替代方法,希望这会有所帮助。您可以创建struct 来容纳玩家对象和武器对象,而不是在各自的类中相互引用。这样,将更容易根据需要进行操作和更改。即一个玩家可以拥有许多武器(在这种情况下,您可以在struct 中创建一个数组)。每个玩家都会有一个与之关联的武器实例。

【讨论】:

  • 有趣的解决方案。但是我也有一个 Map 类。将 Creatures 添加到地图非常直观,但是将 CreatureStruct 添加到地图对于我的游戏引擎的用户来说会感觉很尴尬。尽管如此,我很高兴你提出了这个,我没有立即想到这个。谢谢!
【解决方案3】:

对象来回引用是很常见的。一个常见的例子是指向父级的指针。你的概念是完全合理的。只要确保你有你的析构函数,这样对象指针就会被清除。

~Weapon() 中,清除Creature 指向武器的指针,反之亦然。

【讨论】:

  • 啊,谢谢你的回答。它的普遍性和合理性让我对此感觉好多了。谢谢!
猜你喜欢
  • 2014-08-04
  • 2013-07-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-16
  • 1970-01-01
  • 2010-12-28
相关资源
最近更新 更多