【问题标题】:Correct initializer list when inheriting from virtual base class without creating diamond problem从虚拟基类继承而不创建菱形问题时更正初始化列表
【发布时间】:2020-06-05 00:58:20
【问题描述】:

所以我知道,当您在继承中创建菱形时,最派生类需要在其初始化列表中显式调用虚拟类的子对象的构造函数。

但是从虚拟类继承而没有创建菱形本身的继承的类呢? 例如Bow 继承自虚拟基类 Weapon,Bow 是否也需要在其初始化列表中调用 Object 的构造函数?为什么?

我对所有的类继承和初始化列表有点纠结,我只需要先清理一下,然后再继续并删除初始化列表中的任何不必要的调用。

Object 的构造函数采用 sf::Vector2f,它是两个浮点数。到目前为止,我已经将 Movable、Weapon 和 Projectile 作为虚拟基类,因为它们是菱形的一部分。

// sf::Vector2f is an SFML data type which consists of two floats

class Object
{
private:
    sf::Vector2f m_pos;
public:
    Object(sf::Vector2f start_pos) {m_pos = start_pos;};
}

class Movable : virtual public Object
{
public:
    Movable(sf::Vector2f start_pos) : Object(start_pos) { ... };
}

class Weapon : virtual public Object
{
public:
    Weapon(float shotDelay, bool isStealth) : Object(sf::Vector2f(0,0)) { ... };
}

class Projectile : public Movable
{
public:
    Projectile (sf::Vector2f startPos, int damage) : Movable(startPos) { ... };
}

class Bow : public Weapon
{
public:
    Bow() : Weapon(BOW_SHOT_DELAY, BOW_STEALTH) { ... };
}

class Grenade : public Weapon, public Projectile
{
public:
    Grenade() : Weapon(GRENADE_SHOT_DELAY, GRENADE_STEALTH) {};//for Weapon
    Grenade(sf::Vector2f startPos) : Projectile(startPos, GRENADE_DAMAGE);//for Projectile
}

【问题讨论】:

  • 请出示您的代码 (minimal reproducible example)。如果你继承,那么你可能想要调用基类的构造函数,无论是否是虚拟的
  • 我删除了我的答案,因为它不是一个好答案。它帮助我找出了我理解中的一个漏洞,但它对您的特定情况没有任何帮助。恳请您再次提供minimal reproducible example
  • 你需要初始化每个直接或间接的虚拟基类,不管有没有钻石。
  • 好吧,给我一些时间给你写一个最小的例子,我认为这是无需代码就能回答的问题
  • 无论你是否找到答案,像这样复杂的多继承层次结构都会让人头疼。鉴于您的示例可能只是您的游戏的一小部分,我建议您考虑使用实体-组件-系统 (ECS) 之类的模式,通过分离数据、功能和交互来简化您的代码。

标签: c++ inheritance multiple-inheritance base-class virtual-inheritance


【解决方案1】:

因此,经过一些研究,有用的 cmets、玩耍和整理我的代码后,我找到了答案以及出了什么问题。我为 Object 构造函数提供了一个默认参数,因此无论我是否将调用包含在类的初始化程序列表中,它都会以这种方式调用。

从虚拟基类继承的类如果没有默认构造函数,则必须在其初始化列表中包含对虚拟基类子对象的构造函数的调用

所以在我的例子中,由于 Bow 继承自从 Object 继承的虚拟基类 Weapon,它的初始化列表将如下所示:

Bow::Bow() : Object(BOW_STARTING_POS), Weapon(BOW_SHOT_DELAY, BOW_STEALTH)
{
  //constructor code
}

为了完整起见,我添加了当没有默认构造函数时 Grenade 初始化列表应该是什么:

Grenade::Grenade() : Object(GRENADE_STARTING_POS), Weapon(GRENADE_SHOT_DELAY, GRENADE_STEALTH)
{
  //weapon constructor code
}

Grenade::Grenade() : Object(GRENADE_STARTING_POS), Projectile(GRENADE_STARTING_POS, GRENADE_DAMAGE)
{
  // projectile constructor code
}

附: grenade 分为两个构造函数,因为我的设计需要这样。在另一种情况下,对于从两个虚拟基类继承的类,您只需要一个构造函数,一个初始化列表可以包含所有构造函数调用,如下所示:

Grenade::Grenade() : Object(GRENADE_STARTING_POS), Projectile(GRENADE_STARTING_POS, GRENADE_DAMAGE), Weapon(GRENADE_SHOT_DELAY, GRENADE_STEALTH)
{
  //constructor code
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-11-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-02-06
    • 2011-06-18
    • 1970-01-01
    相关资源
    最近更新 更多