c++中的多级继承(CRTP)
Multilevel inheritance in c++ (CRTP)
请帮我解决这个问题。WhiteDragon
将调用Dragon::attacks()
而不是MonsterImplement::attacks()
,这里存在歧义误差。如果我将Dragon更改为从MonsterImplement派生,然后行std::cout << monster->numAttacks << std::endl;
不会编译,因为Dragon没有numAttacks
数据成员(也不应该编译,因为不同类型的Dragon将具有不同的值(。因此,我需要WhiteDragon
来调用Dragon::attacks()
,并在其实例化期间调用finalizeMonster()
。如果我让Dragon成为Monster的虚拟派生类,WhiteDragon会调用MonsterImplement::attcks((。
#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();
}
(复制自先前的评论。(
视角#1
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()
//摘要 - 虚拟
attack()
//摘要
Dragon
定义:
- virtual
attack()
//concrete,覆盖Monster.attack((
MonsterImplement<...>
定义:
- 虚拟
attack()
//混凝土,覆盖Dragon.attack((和Monster.attack((
WhiteDragon
定义:
- (未定义新的虚拟方法(
很明显,"修复错误后",MonsterImplement.attack()
将被调用,因为它是Dragon的子类,因此会覆盖它。
一般来说,它只是说当前的继承层次结构设计得很糟糕,没有人能够修复它
透视图#2
通过CRTP模式注入一个静态int
很少是值得的。CRTP更适合以一种不会被重写的方式注入一组非静态、非虚拟方法("样板"(,从而避免每个派生类重新实现相同的"样板"。
至少,将静态int numAttacks
转换为虚拟功能
virtual int numAttacks() const { throw std::exception(); }
或
virtual int numAttacks() const = 0; // abstract
然后在CCD_ 26中提供了返回3的具体实现。
struct WhiteDragon : ...
{ ...
virtual int numAttacks() const override { return 3; }
...
};
template <class MONSTER, int NUM>
struct MonsterInt: virtual public Monster {
static int numAttacks;
};
这门课的目的是什么?它所做的似乎只是给一个类一些攻击,在这种情况下,从怪物身上派生是没有意义的。
template <int NUM>
struct MonsterInt {
static int numAttacks;
};
我认为这"修复"了程序,但很难说,因为很难从代码中得出意图。
- 继承函数的重载解析
- 继承期间显示未知行为的子类
- 头文件-继承c++
- 为什么在保护模式下继承升级不起作用
- 通过继承类使用来自不同命名空间的运算符
- 子目录是否继承属性,例如add_definitions,include_directories和父Cmakelist.t
- 尝试使用继承和模板实现CRTP.Visual Studio正在生成编译器错误
- 将实现从继承的 CRTP 注入到继承的接口类
- 使用 CRTP 进行选择性静态成员继承
- 仅函数的多重继承 - 没有虚拟和 CRTP
- 有没有一种干净(更)的方法将 CRTP 与可变参数继承混合在一起?
- 获取 CRTP 继承链中最深的类
- CRTP 和复制/移动赋值/构造函数继承
- C++泛型编程 CRTP 基类继承自派生类型提供的类
- 使用继承时,带有 CRTP 的类型定义不起作用
- 通过CRTP类继承的模板化派生类,访问基类成员对象
- 重载CRTP和其他模板的继承
- CRTP 继承中的基类"friending"是否也会影响子类?
- 带有继承历史的CRTP插件自动注册(尝试使用SFINAE,但失败)
- c++中的多级继承(CRTP)