Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
是否可以使用继承在c++;? 我试图用C++来构造一个游戏,作为一个实体/组件系统(基本的想法是,我将有一组代表不同类型数据的实体”和一组“代表”实体,它们代表一个给定实体可能有的行为。我想使用组件的虚拟基类来实现它。例如,我可以有一个字符实体: class Character { public: int armor; int health; std::string name; };_C++_Oop_Design Patterns_Entity - Fatal编程技术网

是否可以使用继承在c++;? 我试图用C++来构造一个游戏,作为一个实体/组件系统(基本的想法是,我将有一组代表不同类型数据的实体”和一组“代表”实体,它们代表一个给定实体可能有的行为。我想使用组件的虚拟基类来实现它。例如,我可以有一个字符实体: class Character { public: int armor; int health; std::string name; };

是否可以使用继承在c++;? 我试图用C++来构造一个游戏,作为一个实体/组件系统(基本的想法是,我将有一组代表不同类型数据的实体”和一组“代表”实体,它们代表一个给定实体可能有的行为。我想使用组件的虚拟基类来实现它。例如,我可以有一个字符实体: class Character { public: int armor; int health; std::string name; };,c++,oop,design-patterns,entity,C++,Oop,Design Patterns,Entity,以及一个战斗机组件,代表可以使用近战武器的东西: class Fighter { public: int damage; virtual Direction attack() = 0; } 还有一个Mage组件,代表可以施放法术的东西 class Mage { public: std::vector<Spell> spellList; virtual Spell cast() = 0; } 及 为了跟踪地图上的所有当前角色,我可以做如下操作 cla

以及一个
战斗机
组件,代表可以使用近战武器的东西:

class Fighter {
public:
    int damage;
    virtual Direction attack() = 0;
}
还有一个
Mage
组件,代表可以施放法术的东西

class Mage {
public:
    std::vector<Spell> spellList;
    virtual Spell cast() = 0;
}

为了跟踪地图上的所有当前角色,我可以做如下操作

class Engine {
public:
    std::vector<std::unique_ptr<Character>> characters;
类引擎{
公众:
std::矢量字符;
我必须将它们直接存储为
字符
(而不是
战士
法师
),但我需要分别处理战士和法师(例如,循环遍历所有
字符
,如果他们可以施放法术,他们会使用近战武器进行攻击).在实际的游戏逻辑中,我如何区分同时实现
Mage
Character
实例和同时实现
Fighter
Character
实例

有没有一个简单的方法来做我想做的事情,或者我应该彻底重新思考我的设计

(注意:这不是实际的代码;在现实世界中,我实际上会使用工厂或其他东西来创建精灵或其他东西,而不是尝试将所有信息放入构造函数中,我可能会以不同的方式分离逻辑,但它说明了我遇到的问题)。

您可以在引擎中使用:

每个字符将覆盖
字符
类的纯虚拟接受方法

class Engine;
class Spell {};
class Direction {};

class Character {
 public:
  virtual void accept(Engine& engine) = 0;
};

class Fighter {
 public:
  virtual Direction attack() = 0;
};

class Mage {
 public:
  virtual Spell cast() = 0;
};
Mage
Fighter
中继承
Character
将包含较少的样板代码。如果您想坚持自己的继承形式,您需要在每个字符中提供一个重载的
accept
方法,该方法只调用
引擎的
visit
函数:

class ElvenMage : public Character, Mage {
 public:
  ElvenMage() {}
  virtual Spell cast() {
    std::cout << "Casting from ElvenMage"
              << "\n";
    return Spell{};
  }

  void accept(Engine& visitor) override { visitor.visit(*this); }
};

class Player : public Character, Fighter, Mage {
 public:
  Player() {}
  virtual Direction attack() {
    std::cout << "Attacking from Player"
              << "\n";
    return Direction{};
  }

  virtual Spell cast() {
    std::cout << "Casting from Player"
              << "\n";
    return Spell{};
  }

  void accept(Engine& visitor) override { 
    // cast to Player if it should attack instead of casting
    visitor.visit(static_cast<Mage&>(*this)); 
  }
};
请注意,我在上面的代码中有一个循环依赖项,在拆分声明和定义时应该解决这个问题。

您可以在引擎中使用:

每个字符将覆盖
字符
类的纯虚拟接受方法

class Engine;
class Spell {};
class Direction {};

class Character {
 public:
  virtual void accept(Engine& engine) = 0;
};

class Fighter {
 public:
  virtual Direction attack() = 0;
};

class Mage {
 public:
  virtual Spell cast() = 0;
};
Mage
Fighter
中继承
Character
将包含较少的样板代码。如果您想坚持自己的继承形式,您需要在每个字符中提供一个重载的
accept
方法,该方法只调用
引擎的
visit
函数:

class ElvenMage : public Character, Mage {
 public:
  ElvenMage() {}
  virtual Spell cast() {
    std::cout << "Casting from ElvenMage"
              << "\n";
    return Spell{};
  }

  void accept(Engine& visitor) override { visitor.visit(*this); }
};

class Player : public Character, Fighter, Mage {
 public:
  Player() {}
  virtual Direction attack() {
    std::cout << "Attacking from Player"
              << "\n";
    return Direction{};
  }

  virtual Spell cast() {
    std::cout << "Casting from Player"
              << "\n";
    return Spell{};
  }

  void accept(Engine& visitor) override { 
    // cast to Player if it should attack instead of casting
    visitor.visit(static_cast<Mage&>(*this)); 
  }
};

请注意,我在上面的代码中有一个循环依赖项,这应该在分解声明和定义时解决。

ECS实际上没有继承性,如果这是您的目标,请再次阅读ECS。游戏引擎通常需要检查对象的类型,因此您将有类似于 动态施法(&someCharachter)
在您当前的设计中,以及使
角色
多态。@路人我知道这应该避免复杂的继承层次结构,但是“所有
角色
都是
法师
的概念可以
施法
”基本上看起来与java的
接口
或c++的虚拟类范例完全相同。而且我知道我必须进行动态转换,我的问题是,我如何知道只要给定一个
字符
实例,它就实现了哪些组件来知道该执行什么cast@RaghavMalik在这个具体案例中,他们非常相似。问题不在于ca在一个对象上使用一个方法,但如何处理数千个对象,每个对象可能包含数百个组件。在这种情况下,它们是非常不同的。实现组件系统的最简单方法是创建一个
GameObject
类,并为其提供指向每个可能组件类型的指针。如果您想要所有的法师,只需在所有对象并抓取那些具有指向
MageComponent的非空指针的对象
ECS实际上没有继承性,如果这是您的目标,请再次阅读ECS。游戏引擎通常需要检查对象的类型,因此您将有类似
dynamic\u cast(&someCharachter)的内容
在您当前的设计中,以及使
角色
多态。@Passenger我知道它应该避免复杂的继承层次结构,但是“所有
角色
都是
法师
的概念可以
施放
”基本上看起来与java的
接口
或c++的虚拟类范例完全相同。而且我知道我必须进行动态转换,我的问题是,我如何知道只要给定一个
字符
实例,它就实现了哪些组件来知道该执行什么cast@RaghavMalik在这个具体案例中,他们非常相似。问题不在于ca在一个对象上使用一个方法,但如何处理数千个对象,每个对象可能包含数百个组件。在这种情况下,它们是非常不同的。实现组件系统的最简单方法是创建一个
GameObject
类,并为其提供指向每个可能组件类型的指针。如果您想要所有的法师,只需在所有对象,并获取具有指向
MageComponent的非空指针的对象
class Engine {
  std::vector<std::unique_ptr<Character>> characters;
  void do_stuff_with_spell(Spell spell) {
    // ...
  }
  void do_stuff_with_attack(Direction direction) {
    // ...
  }

 public:
  void visit(Mage& mage) { do_stuff_with_spell(mage.cast()); }
  void visit(Player& player) { do_stuff_with_attack(player.attack()); }

};