0
votes

So I get that when you create a diamond in inheritance the most derived class needs to explicitly call the constructor of the virtual class's sub-objects in its initializer list.

But what about classes that inherit from a virtual class without that inheritance creating a diamond itself? e.g. Bow inherits from virtual base class Weapon, does Bow need a call to Object's constructor in its initializer list too and why?

I've become a bit tangled with all the classes inheritances and initializer lists and I just need to clear things up first before continuing and remove any unnecessary calls in my initializer lists.

Object's constructor takes a sf::Vector2f which is two floats. So far I've had Movable, Weapon and Projectile as virtual base classes since they are part of the diamond.

enter image description here

// 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
}
1
Please show your code (minimal reproducible example). If you inherit then you may want to call the constructor of the base class, whether virtual or not463035818_is_not_a_number
I deleted my answer, because it wasnt a good one. It helped me to identify a hole in my understanding but it didnt help anything for your particular situation. I kindly ask you again to provide a minimal reproducible example463035818_is_not_a_number
You need to initialise every direct or indirect virtual base class, regardless of having or nit having a diamond.n. 1.8e9-where's-my-share m.
okay give me some time to write a minimal example for you, I thought it was something that could be answered without codeYiannis
Whether you find your answer or not, complex multi-inheritance hierarchies like this are going to cause a headache. Given that your example is probably a small slice if your game, I recommend considering a pattern like Entity-Component-System (ECS) to simplify your code by separating data, capabilities and interactions.parktomatomi

1 Answers

0
votes

So after some research, the helpful comments, playing around and tidying up my code I figured out the answer and what was going wrong. I was supplying the Object constructor with a default argument so it was being called that way whether I included the call in the initializer list of a class or not.

A class that inherits from a virtual base class must include calls the constructors of the virtual base class's sub-objects in its initializer list if they do not have default constructors.

So in my example, since Bow inherits from virtual base class Weapon which inherits from Object, its initializer list will look like this:

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

For completeness I'm adding what the Grenade initializer lists should be when there is no default constructor:

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. grenade is split into two constructors because my design required it that way. In a different case where you only need one constructor for a class inheriting from two virtual base classes, one initializer list can contain all the constructor calls as such:

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