关于c ++:从虚拟基类继承而没有创建菱形问题时,正确的初始化列表

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

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

但是,从一个虚拟类继承而又没有创建钻石本身的继承的类呢? 例如 Bow继承自虚拟基类Weapon,Bow是否也需要在其初始值设定项列表中调用Object的构造函数,为什么?

我对所有的类继承和初始化器列表都有些纠结,我只需要先清除所有内容,然后再继续并删除初始化器列表中的所有不必要的调用。

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

enter image description here

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// 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构造函数提供了一个默认参数,因此无论我是否将该调用包含在类的初始化列表中,都以这种方式调用它。

从虚拟基类继承的类必须在其初始化程序列表中包括调用虚拟基类的子对象的构造函数(如果它们没有默认构造函数)。

因此,在我的示例中,由于Bow继承自从对象继承的虚拟基类Weapon,因此其初始化程序列表如下所示:

1
2
3
4
Bow::Bow() : Object(BOW_STARTING_POS), Weapon(BOW_SHOT_DELAY, BOW_STEALTH)
{
  //constructor code
}

为了完整起见,我添加了没有默认构造函数时Grenade初始化程序列表应为的内容:

1
2
3
4
5
6
7
8
9
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
}

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

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