关于模板和虚函数的问题
Problem about templates and virtual function
我有模板问题 - 虚函数不匹配。
首先,我有一个 parent class 名为 Unit
和 2 child class 名为 Hero
和 Monster
。
这 2 classes 有 2 个 subclasses 并且 class Hero 的 subclass 之一是 Crusader
.
class Unit {
template <typename target>
virtual void Attack(typename std::vector<target>::iterator targetPtr, std::shared_ptr<AttackSkill> skillPtr) {}
//ERROR (template function can not be virtual)
};
class Hero : public Unit {
template <typename target>
virtual void Attack(typename std::vector<target>::iterator targetPtr, std::shared_ptr<AttackSkill> skillPtr) {}
// ERROR (template function can not be virtual)
};
class Crusader : public Hero {
template <typename target>
void Attack(std::vector<target>::iterator targetPtr, std::shared_ptr<AttackSkill> skillPtr) {}
};
// Unit vector that contains heroes and monsters
std::vector<Unit> unitVector;
Crusader crusader1;
unitVector.at(0).emplace_back[crusader1];
问题是,我想通过将 virtual void Attack
函数写入 Hero
class 和 Unit
来从 unitVector[0]
访问 Attack
函数class
但不幸的是 C++ 不允许这样做。
怎么写这些虚函数呢?
或者我可以使用一些通用指针(如果有这样的东西)而不是模板吗?
我想使用来自不同怪物和不同英雄的攻击功能,所以我必须使用模板。如果我尝试编写不同的函数,例如 attackHero
和 attackMonster
,其中一个不起作用,因为当我这样做时,我基本上是在尝试获取一些 non-existent [= 的迭代器34=]的向量。
请帮帮我!
您的代码应如下所示:
class IUnit
{
public:
virtual void attack(IUnit& target, const AttackSkill& skill) = 0;
};
class Hero : public IUnit
{
public:
virtual void attack(IUnit& target, const AttackSkill& skill) override { /* do something */ }
};
class Crusader final : public Hero
{
public:
void attack(IUnit& target, const AttackSkill& skill) final { /* do something else */}
};
函数模板是在编译时确定的(静态多态性) ,并且我们使用虚函数来确定应该在 运行-time 上调用哪个函数(dynamic多态性),因此,不可能将两者结合起来。你应该阅读 this question for more information
这里,你想创建一个attack(target, skill)
函数,根据攻击单位(一般接口用I表示),赋予使用的攻击技能,使用提供的技能。它可以对任何类型的IUnit
进行操作,每个IUnit
都应该实现它。
假设我们实施了 class monster
,我们可以使用如下攻击:
class Monster : public IUnit
{
public:
virtual void attack(IUnit& target, const AttackSkill& skill) override { /* placeholder */ }
};
int main()
{
Monster some_monster{};
Crusader some_crusader{};
some_crusader.attack(some_monster, AttackSkill{});
}
一些小评论:
- 使用关键字
override
告诉编译检查它确实正确地覆盖了虚函数,它可以节省你很多调试!
- 使用关键字
final
告诉编译器没有其他 class 应该从 class Crusader
继承(您可以通过 替换 override
为 final
).
模板不是您在这里需要的工具。多态性是。
当您有相似或相同的代码必须处理多个不相关的类型时,模板很有用。当您有一组直接相关的类型都需要做不同的事情时,多态性很有用。
在这里,你有圣教军、英雄和怪物,它们攻击、受到伤害和移动的方式都不同,但它们都是不同的单位,这意味着它们都直接相关,属于第二类.
现在,理论很好,但我们更关心的是实施而不是理论...
要解决此问题,您需要进行两个修复。
首先,class 定义不正确 - 我们不需要任何模板内容,因此我们可以摆脱所有这些。
class Unit
{
public:
Unit();
virtual ~Unit();
virtual void Attack(std::shared_ptr<Unit> Target, const AttackSkill& skill);
};
...
class Hero : public Unit
{
public:
Hero();
virtual ~Hero();
virtual void Attack(std::shared_ptr<Unit> Target, const AttackSkill& Skill) override;
};
...
class Crusader : public Hero
{
public:
Crusader();
~Crusader();
void Attack(std::shared_ptr<Unit> Target, const AttackSkill& Skill);
};
在这里,我假设 Crusader 没有任何子classes - 如果有,请确保析构函数和 Attack()
都是虚拟的。
现在,第二个主要变化是您的收集和插入方法:
std::vector<std::shared_ptr<Unit>> Units;
...
Units.emplace_back(std::make_shared(new Crusader());
这里的主要区别在于指针的使用。 C++ 中的多态性基本上要求您使用指针 - 使用不带指针的普通对象将导致编译器 "slice" 您的 class,删除您的任何自定义行为。如果你添加一个圣洁修饰符作为十字军 class 的成员,然后尝试从 "sliced" class 访问它,这将成为一个主要问题 - 程序将立即崩溃,因为"slicing" 从对象中删除不在基础 class 中的任何内容。
为了让它们有点 "nicer" 使用,我将这里的指针包装在 std::shared_ptr
中。当没有更多引用时,这提供了自动引用计数和销毁。但是,无论您使用 std::shared_ptr
还是原始指针,都适用相同的规则。
我有模板问题 - 虚函数不匹配。
首先,我有一个 parent class 名为 Unit
和 2 child class 名为 Hero
和 Monster
。
这 2 classes 有 2 个 subclasses 并且 class Hero 的 subclass 之一是 Crusader
.
class Unit {
template <typename target>
virtual void Attack(typename std::vector<target>::iterator targetPtr, std::shared_ptr<AttackSkill> skillPtr) {}
//ERROR (template function can not be virtual)
};
class Hero : public Unit {
template <typename target>
virtual void Attack(typename std::vector<target>::iterator targetPtr, std::shared_ptr<AttackSkill> skillPtr) {}
// ERROR (template function can not be virtual)
};
class Crusader : public Hero {
template <typename target>
void Attack(std::vector<target>::iterator targetPtr, std::shared_ptr<AttackSkill> skillPtr) {}
};
// Unit vector that contains heroes and monsters
std::vector<Unit> unitVector;
Crusader crusader1;
unitVector.at(0).emplace_back[crusader1];
问题是,我想通过将 virtual void Attack
函数写入 Hero
class 和 Unit
来从 unitVector[0]
访问 Attack
函数class
但不幸的是 C++ 不允许这样做。
怎么写这些虚函数呢?
或者我可以使用一些通用指针(如果有这样的东西)而不是模板吗?
我想使用来自不同怪物和不同英雄的攻击功能,所以我必须使用模板。如果我尝试编写不同的函数,例如 attackHero
和 attackMonster
,其中一个不起作用,因为当我这样做时,我基本上是在尝试获取一些 non-existent [= 的迭代器34=]的向量。
请帮帮我!
您的代码应如下所示:
class IUnit
{
public:
virtual void attack(IUnit& target, const AttackSkill& skill) = 0;
};
class Hero : public IUnit
{
public:
virtual void attack(IUnit& target, const AttackSkill& skill) override { /* do something */ }
};
class Crusader final : public Hero
{
public:
void attack(IUnit& target, const AttackSkill& skill) final { /* do something else */}
};
函数模板是在编译时确定的(静态多态性) ,并且我们使用虚函数来确定应该在 运行-time 上调用哪个函数(dynamic多态性),因此,不可能将两者结合起来。你应该阅读 this question for more information
这里,你想创建一个attack(target, skill)
函数,根据攻击单位(一般接口用I表示),赋予使用的攻击技能,使用提供的技能。它可以对任何类型的IUnit
进行操作,每个IUnit
都应该实现它。
假设我们实施了 class monster
,我们可以使用如下攻击:
class Monster : public IUnit
{
public:
virtual void attack(IUnit& target, const AttackSkill& skill) override { /* placeholder */ }
};
int main()
{
Monster some_monster{};
Crusader some_crusader{};
some_crusader.attack(some_monster, AttackSkill{});
}
一些小评论:
- 使用关键字
override
告诉编译检查它确实正确地覆盖了虚函数,它可以节省你很多调试! - 使用关键字
final
告诉编译器没有其他 class 应该从 classCrusader
继承(您可以通过 替换override
为final
).
模板不是您在这里需要的工具。多态性是。
当您有相似或相同的代码必须处理多个不相关的类型时,模板很有用。当您有一组直接相关的类型都需要做不同的事情时,多态性很有用。
在这里,你有圣教军、英雄和怪物,它们攻击、受到伤害和移动的方式都不同,但它们都是不同的单位,这意味着它们都直接相关,属于第二类.
现在,理论很好,但我们更关心的是实施而不是理论...
要解决此问题,您需要进行两个修复。
首先,class 定义不正确 - 我们不需要任何模板内容,因此我们可以摆脱所有这些。
class Unit
{
public:
Unit();
virtual ~Unit();
virtual void Attack(std::shared_ptr<Unit> Target, const AttackSkill& skill);
};
...
class Hero : public Unit
{
public:
Hero();
virtual ~Hero();
virtual void Attack(std::shared_ptr<Unit> Target, const AttackSkill& Skill) override;
};
...
class Crusader : public Hero
{
public:
Crusader();
~Crusader();
void Attack(std::shared_ptr<Unit> Target, const AttackSkill& Skill);
};
在这里,我假设 Crusader 没有任何子classes - 如果有,请确保析构函数和 Attack()
都是虚拟的。
现在,第二个主要变化是您的收集和插入方法:
std::vector<std::shared_ptr<Unit>> Units;
...
Units.emplace_back(std::make_shared(new Crusader());
这里的主要区别在于指针的使用。 C++ 中的多态性基本上要求您使用指针 - 使用不带指针的普通对象将导致编译器 "slice" 您的 class,删除您的任何自定义行为。如果你添加一个圣洁修饰符作为十字军 class 的成员,然后尝试从 "sliced" class 访问它,这将成为一个主要问题 - 程序将立即崩溃,因为"slicing" 从对象中删除不在基础 class 中的任何内容。
为了让它们有点 "nicer" 使用,我将这里的指针包装在 std::shared_ptr
中。当没有更多引用时,这提供了自动引用计数和销毁。但是,无论您使用 std::shared_ptr
还是原始指针,都适用相同的规则。