请帮我解决这个问题。 WhiteDragon
将调用Dragon::attacks()
而不是MonsterImplement::attacks()
std::cout << monster->numAttacks << std::endl;
,这里存在歧义错误。如果我改变龙
从MonsterImplement派生,然后就行了
numAttacks
不会编译,因为Dragon没有WhiteDragon
数据成员(也不应该,因为不同类型的Dragons具有不同的值)。因此,我需要Dragon::attacks()
来调用finalizeMonster()
并在实例化期间调用#include <iostream>
struct Monster {
virtual void finalizeMonster() {}
virtual void attack() {}
};
template <class MONSTER, int NUM>
struct MonsterInt: virtual public Monster {
static int numAttacks;
};
template <class MONSTER, int NUM>
int MonsterInt<MONSTER, NUM>::numAttacks = NUM;
template <class BASE, class MONSTER>
struct MonsterImplement: virtual public BASE {
MonsterImplement() {finalizeMonster();}
virtual void finalizeMonster() override;
virtual void attack() override {std::cout << "MonsterImplement::attack()" << std::endl;}
};
struct Dragon: public Monster { // or Dragon: public MonsterImplement<Monster, Dragon> ?
// but then Dragon will also call the MonsterImplement constructor (when it has no numAttacks member)
virtual void attack() override {std::cout << "Dragon::attack()" << std::endl;}
};
struct WhiteDragon: public MonsterInt<WhiteDragon, 3>,
public MonsterImplement<Dragon, WhiteDragon> {
WhiteDragon(): MonsterImplement<Dragon, WhiteDragon>() {}
};
template <class BASE, class MONSTER>
inline void MonsterImplement<BASE, MONSTER>::finalizeMonster() {
MONSTER* monster = static_cast<MONSTER*> (this);
std::cout << monster->numAttacks << std::endl;
}
int main() {
WhiteDragon wd;
wd.attack();
}
。如果我使Dragon虚拟派生类Monster,WhiteDragon会调用MonsterImplement :: attacks()。
{{1}}
答案 0 :(得分:3)
(复制自之前的评论。)
CRTP旨在提供非动态行为。如果“numAttacks”的值随每个派生类而变化,则这不是“非动态”情况。反例是将非静态非虚方法int numAttacks() { return 3; }
放在派生类中,然后在CRTP基类中添加一些方法(在所有派生类之间共享的攻击逻辑),然后可以在其派生类上调用numAttacks()
方法,而不会产生虚函数调用。
示例:
struct Monster
{
virtual void attack() = 0;
virtual int getNumAttacks() const = 0;
};
template <struct MONSTER>
struct AttackLogic : virtual public Monster
{
virtual void attack() override
{
/* allowed to call MONSTER::getNumAttacks(), renamed to avoid confusion. */
int numAttacks = static_cast<MONSTER*>(this).getNumAttacks();
/* Use the value in attack calculations. */
}
};
struct Unicorn
: virtual public Monster
, virtual public AttackLogic<Unicorn>
{
virtual int getNumAttacks() const override
{
return 42; // Unicorn is awesome
}
};
免责声明:代码仅用于解释我的建议。不适合实际使用。没有用编译器测试过。我对虚拟遗传的了解很少,因此上面的示例代码中可能存在错误或违反准则。
您当前的继承链是:(位于顶部)
Monster
Dragon
MonsterImplement<Dragon, WhiteDragon>
WhiteDragon
Monster
定义:
finalizeMonster()
// abstract attack()
// abstract Dragon
定义:
attack()
//具体,覆盖Monster.attack() MonsterImplement<...>
定义:
attack()
//具体,覆盖Dragon.attack()和Monster.attack() WhiteDragon
定义:
很明显“修复bug后”会调用MonsterImplement.attack()
,因为它是Dragon的子类,因此会覆盖它。
一般来说,它只表示当前的继承层次结构设计糟糕,并且没有人能够修复它。
通过CRTP模式注入静态int
很少值得付出努力。 CRTP更适合以不会被覆盖的方式注入一组非静态非虚方法(“样板”),这样可以避免每个派生类重新实现相同的“样板”。
至少将静态int numAttacks
转换为虚函数
virtual int numAttacks() const { throw std::exception(); }
或
virtual int numAttacks() const = 0; // abstract
然后在WhiteDragon
中提供具体实现以返回3.
struct WhiteDragon : ...
{ ...
virtual int numAttacks() const override { return 3; }
...
};
答案 1 :(得分:0)
template <class MONSTER, int NUM>
struct MonsterInt: virtual public Monster {
static int numAttacks;
};
这门课的目的是什么?它似乎只是给了一个类一些攻击,在这种情况下,从怪物派生出来并没有多大意义。
template <int NUM>
struct MonsterInt {
static int numAttacks;
};
那&#39;修复&#39;我认为这个程序,但很难真正说出来,因为很难从你的代码中得到意图。