是否可以使用继承在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()); }
};