C ++ - 允许类中的访问对象访问它们所在的类的推荐方法

时间:2013-12-16 06:07:28

标签: c++ organization

我有一个课程Game,课程为EnemyManagerEnemyManager处理敌人的产生及其背后的逻辑。问题是EnemyManager需要访问游戏类中的函数和其他Game对象。我可以想到两种方法来解决这个问题。

  1. 使用Game*作为this中的参数之一传递类对象EnemyManager的地址。

  2. 声明一个指向Game对象的全局指针,并在初始化Game类时设置它。然后将其extern到enemymanager.cpp

  3. 这是更明智的方法吗?

5 个答案:

答案 0 :(得分:4)

每当遇到这样的情况时,我都会检查相关课程的整体设计。如果EnemyManager是Game对象的成员并且需要在Game中调用内容,那么Game中的那些函数可以被分解为一个单独的组件。如果你正在写的东西开始变得过于复杂或者像是黑客,那么通常是时候做一些保理。

答案 1 :(得分:1)

很难说不知道整体架构布局,但我的2美分:

您描述为第一个的方式称为dependency injection,并且被广泛使用。你应该留意你正在公开的方法/领域。 我假设Game类具有不应该从EnemyManager类访问的方法,因此看起来创建具有{所使用的方法的声明的接口的接口似乎是个好主意。 {1}}然后将指针传递给EnemyManager实例(而不是EnemyManager)。

例如:Game类实现Game,并且您使用此作为初始化参数之一传递IGameEnemyManager

答案 2 :(得分:1)

在处理面向对象的设计时,通常会考虑谁将如何处理如何找到设计的第一个版本。在编写了这个版本之后,人们经常会发现这些弱点并在第二次迭代时重写它。

因此,在这种情况下,Game类管理世界(我假设)并提供不同的方法来操纵它。你的EnemyManager管理世界的一个方面,敌人,但他们确实生活在世界的内部。

class Enemy {
public:
  Enemy(Location& location, int hitpoints);
  bool Move(Direction& direction);
};

class Game {
public:
  bool CreateInitialState();
  bool AddEnemy(Enemy& enemy);
  bool AddBullet(Location& location, Direction& direction, int speed);
  void Render();
};

class EnemyManager {
public:
  EnemyManager(Game& game);
  void MoveEnemies();
};

在第一个版本中,所有类型都将相互视为正确的类,并通过调用适当的方法来操作事物。如果你想为它添加新东西,这对扩展游戏几乎没有支持。

这就是接口变得方便的地方,您可以尝试考虑不同部分的交互方式,而不是如何实现它们。

class Canvas {
public:
  // Different graphical primitives.
};

class GameObject {
public:
  virtual ~GameObject() {};
  virtual void Draw(Canvas& canvas) = 0;
  virtual bool Move(Direction& direction) = 0;
};

class GlobalState {
public:
  virtual AddGameObject(GameObject& gameObject) = 0;
};

class Game : public Canvas, public GlobalState {
public:
  bool CreateInitialState();

  void Render() {
    // Send itself to the Draw method in all GameObjects that have been added
  }

  // Other game logic
};

class Enemy : public GameObject {
  // This can be specialized even more if you need to
};

class Bullet : public GameObject {
  // This can also be specialized even more if you need to
};

这将设计与实施区分开来,正如我所看到的,这是一种最终尝试正确的好方法。

答案 3 :(得分:0)

如果您在game objects中处理EnemyManager,为什么它会成为课程Game的一部分?我想你应该考虑检查你的设计,因为如果你不能很好地处理这些情景,就有机会出现循环引用问题。

Consider segregating both the classes to ensure a single responsibility principle.
Define proper interface in your
{EnemyManager {1}}

这些是我能想到的关于你的设计的有限想法的小建议

答案 4 :(得分:0)

您绝对需要使用第一种方法,但只需进行一些更改:您应该将Game类分解为更多组件。例如,您可以创建一个SceneManager类,它负责所有游戏对象的创建/管理。当您实例化EnemyManager时 - 只需传递指向它的指针:

// in SceneManager
EnemyManager* emgr = new EnemyManager(this);
InterfaceManager* imgr = new InterfaceManager(this);

请注意,您的SceneManager类应提供完整的界面

// in EnemyManager
GameObject* spawnEnemyAt(string name, EnemyClass* eclass, Vector3 position, AIBehaviour* behaviour)
{
    GameObject* myEnemy = smgr->createGameObject(name, position, etc...);
    //register an enemy in the enemies list, initialize it's behaviour and do any other logic

    return myEnemy
}

这种方法可以帮助您破坏您的架构,而不是在friend(类)区域中捕获。


[更新] 请注意,我的方法假设场景中的所有对象都是GameObject s,既没有Enemy也没有Player类。每个GameObject 可能都有RendererAnimatorAIBehaviour个组件。