从虚拟基 class 继承时更正初始化列表而不产生菱形问题

Correct initializer list when inheriting from virtual base class without creating diamond problem

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

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

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

对象的构造函数接受一个 sf::Vector2f,它是两个浮点数。到目前为止,我已经将 Movable、Weapon 和 Projectile 作为虚拟基础 classes,因为它们是钻石的一部分。

// 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
}

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

从虚拟基 class 继承的 class 必须在其初始化列表中调用虚拟基 class 的子对象的构造函数如果他们没有默认构造函数.

因此在我的示例中,由于 Bow 继承自虚拟基础 class Weapon 继承自 Object,因此其初始化列表如下所示:

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
}

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

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