【问题标题】:C++ object interactionC++ 对象交互
【发布时间】:2013-05-10 07:36:02
【问题描述】:

对于我正在编写的程序,我在 C++ 中创建了一个充满动物实体的 2d 世界。我有一个世界级和实体类(以及从实体继承的一系列不同类型的实体)。

我希望实体“知道”它所在的世界并能够与实体的二维数组进行良好交互,但我不希望它从世界继承(毕竟,实体 不是 世界)。所以我只是想获得一些想法来实现这个的好方法。我当然可以让每个实体都包含一个指向它所在世界的指针,但它看起来相当混乱。有没有更简单的方法让二维数组中的实体“知道”哪个世界对象包含它。

在c++中有什么方法可以让一个对象作为另一个对象的成员变量来知道包含它的对象吗?

谢谢!

【问题讨论】:

  • ...我正要说“为什么每个实体都没有指向他所居住的世界的指针?”... :)
  • 我会选择指针。
  • 好像有点循环,有没有别的办法?
  • 父母认识儿子,儿子认识父母,是否循环?
  • “循环”本身不是问题。特别是因为关系不是对称的:世界包含实体(拥有它们),但实体只相同的世界你在黑夜里看星星的方式。 “看,不要碰”指针是一种相当有用的模式。

标签: c++ class object inheritance


【解决方案1】:

我有一个世界级的

亲爱的。


除此之外,您的实体与其环境的有意义的交互是什么?它是否应该能够查询任意信息、查看地平线、询问其他实体的状态?

或者它应该有一些有限的视野,基于它的位置和属性?

在第一种情况下,它显然是一个神一般的实体,不适用诸如封装和关注点分离之类的普通关注点。

在第二种情况下,公开一个接口(您可以将其抽象化以减少耦合),使其只看到它应该看到的内容。


好的,所以第二种情况可能看起来像

class World; // is a dumb container of entities
class Environment; // is an entity's window on the world
class Entity {
public:
    void take_a_turn(Environment&) = 0;
};
class Environment {
public: // control what an entity can do to (see of) the World
    container<const Entity*> visible_entities() const;
    result attempt_to_eat(const Entity*);
    result attempt_to_mate(const Entity*);
    result run_away_from(const Entity*);
};

当然,如果您的 Entity 对象是活动的(即,它们在自己的线程中自主且连续地运行),它们需要保留指向世界或环境。

但是,如果您只是调用它们,一次一个,当它们有机会做某事时,每次都传递引用就可以了。

【讨论】:

  • “天哪。”为何如此?第二种情况更符合我的要求,您将如何“公开界面”/设置与其环境的交互?
  • 向你最喜欢的搜索引擎询问god class antipattern,看看为什么world class这个短语会立即令人担忧。
【解决方案2】:

假设我的理解正确,每个实体中的世界指针的替代方法是给每个世界一个唯一的 id,然后将该 id 存储在实体中,因为它被添加到它的世界中。

【讨论】:

  • 带有中介对象,例如 WorldManager(WM) 单例类。 WM 有一个世界列表,每个世界都有一个唯一的 id,并且 WM 具有需要世界 id 作为参数来识别您要访问的世界的访问器函数。然后每个实体存储其所在世界的 id,当它想要访问世界数据时,它会抓取单例 WM 并调用相关函数。您可以对 Entity 对象执行相同的操作,同样每个对象都有自己的 id 并存储在 EntityManager 中。如果您即时创建/销毁大量对象,这非常有用;没有意外的 NULL 指针取消引用。
【解决方案3】:

聚合(为每个实体提供一个世界指针)是最简单的解决方案。另一种解决方案是使用第三个mediator object,它维护指向世界和实体的指针,存储它们的关系,并调解(因此得名)它们之间的通信。这个对象可能是一个全局单例(大多数程序员会不寒而栗,但我不认为其中一些是坏事),或者每个世界和实体都需要一个指向 it 的指针来进行通信,这显然不是第一个解决方案的大改进。

【讨论】:

    【解决方案4】:

    也许你可以为世界创造某种全球引擎。引擎将有系统,世界可以被认为是引擎内部的系统。您将在实体的构造函数中向引擎请求世界系统,并在其中执行您需要的操作。

    class World : public System
    {
      // info in here
    }
    
    
    class Engine 
    {
      public:
        World * getWorldSystem(); // Not as good
        System * getSystem( std::string name ); // uses lookup, convert to right type
    
    }
    

    引擎类的问题是“我如何引用它?”在大多数情况下,您会包含引擎的 .h 文件,该文件还具有:

    extern Engine * ENGINE;
    

    在其中,我理解这很可怕,但是对于引擎/系统架构,您必须在某个地方拥有它。或者你明确地使用单例。

    至于你的继承树可能会完全改变你的设计方案。基于组件的架构可能是您解决此问题的一种方式。

    虽然在很多情况下继承都是有意义的,但构建基于组件的实体将帮助您处理每只动物必须拥有的大量奇怪类型。

    拍摄:

    class Component
    {
      public:
        Component();
        virtual ~Component();
    
    }
    
    class WalkComponent : public Component
    {
      public:
        Walk(); // Something here allows the entity to walk on the ground
    }
    
    class FlightComponent : public Component
    {
      public:
        Fly(); // Something in here moves the entity around using flight
    }
    

    您马上就可以看到,您可以将 walk 组件和 flight 组件附加到实体,它会同时拥有这两者,而不是尝试创建允许这两者的继承树。

    【讨论】:

    • 这是一个非常有趣的想法。这种设计结构有名称吗?我想进一步研究它。你有使用这个的开源游戏的例子吗?
    • 系统/组件架构,elephant.codeplex.com 。这个答案也可能会有所启发,回答者提到不使用组件设计但他有很多资源:stackoverflow.com/questions/1901251/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多