1

I'm currently trying to build a hierarchy of classes that uses multiple inheritance. I have classes A, B, C and D, related as such:

struct A
{
    int a;
    A(int a_) : a(a_) {}
};

struct B : virtual A
{
    int b;
    B(int a_, int b_) : A(a_), b(b_) {}
};

struct C : virtual A
{
    C(int a_) : A(a_) {}
};

struct D : B , C
{
    D(int a_, int b_) : A(a_), B(a_, b_) , C(a_) {}
};

My problem is that D is passing arguments to B and C that aren't needed, and I'd like to find a better way of doing this.

The best way I found would be to have D initialize B first with B(a_, b_) and then B would initialize A with A(a_) and then I'd initialize C with C(a_) (even though the argument wouldn't matter) and 'link' C's instance of A to B's A instance.

What I mean by this is that the memory layout of D would look something like this:

Memory Layout

Where C's base class A would be located inside of B.

I've tried multiple ways to do this in C++, but I haven't found one where it would let me change where C's A was located nor do I know if it possible.

My question is if this is possible to achieve in C++ using inheritance or possibly another tool?


Even if it possible, I would still have the problem of having to initialize both B and C with a 'dummy' argument that wouldn't do anything, this is fine for an int, but not for something more 'heavy'.

What I would want is for, when inheriting from B or C, you'd use an empty constructor to initialize it, and would use the other constructor when creating it normally, something like this:

struct A
{
    int a;
    A(int a_) : a(a_) {}
};

struct B : virtual A
{
    int b;
    B(int a_, int b_) : A(a_), b(b_) {}

    protected:

    // The A initialization will never get called
    B(int b_) : A(0), b(b_) {}
};

struct C : virtual A
{
    C(int a_) : A(a_) {}

    protected:

    // This initialization will never get called
    C() : A(0) {}
};

struct D : B , C
{
    D(int a_, int b_) : A(a_), B(b_) , C() {}
};

The only problem is that I'm not sure this has any side effects I should be aware of, or if it even works, I couldn't think of a way to test it well.

I'm not sure if asking two questions in one is acceptable, I believe that they make sense together, but if not, I'll edit it out and ask it as a different question.

Edit 1:

In relation to the duplicate, that answer states that the unused arguments will not be used to initialize the base-most class in the two derived classes.

My second question is how can I avoid having to provide the unused parameters to the two derived classes as the arguments can be very big and take a long time and memory copying. I have provided a possible solution, but I am not sure if this actually solves my problem and what side effects it can have.

Thus more concretely, my second question is Is this implementation of avoiding providing the parameters to the two derived classes good or are there any side effects I haven't taken in to account while building it?

Filipe Rodrigues
  • 1,843
  • 2
  • 12
  • 21
  • Possible duplicate of [Diamond Inheritance Lowest Base Class Constructor](https://stackoverflow.com/questions/12500230/diamond-inheritance-lowest-base-class-constructor) – Douglas Oliveira May 07 '19 at 05:47
  • @DouglasOliveira Thank you for the link, but unfortunately, they only confirm that the initialization will not occur, they do not talk about how you can avoid having to provide the not needed arguments to the constructor. – Filipe Rodrigues May 07 '19 at 05:58
  • If you put a default constructor at A, then you don't need to call it at B and C. Use `protected: A() = default;` – Douglas Oliveira May 07 '19 at 06:22
  • @DouglasOliveira In my use case, A is actually `std::runtime_error`, which doesn't have a default constructor and I cannot modify. From a language standpoint, in the protected constructor of B and C, A's initializer will never be called, by definition, so I thought there might have been a way to simply avoid it outright, because while I could just write ` : A(0) ` and be done with it, since it won't ever be called, there are some classes that might take a reference in the constructor for example, this would mean that I could not simply write that. – Filipe Rodrigues May 07 '19 at 06:32
  • @DouglasOliveira There is also the point that, even if I defaulted it, if it had any members that needed to be initialized, it would need to do that, so the problem was just moved from one place to another. – Filipe Rodrigues May 07 '19 at 06:37
  • There already is a single `A` object with virtual inheritance, so your picture is more or less accurate. Maybe you should edit your question to make it clear that you’re after a non-redundant means of constructing such an object. – Davis Herring May 08 '19 at 01:28
  • @DavisHerring Well the redundant way to construct this object is just the 2nd part, what I really want to for `D` to not have to initialize `A` in it's constructor and instead let `B` do it, then have `C` use `B`'s instance of `A` as it's base class. Basically I want to make `D` be as simple as possible without even having to write any constructors and just inheriting `B`'s constructors. – Filipe Rodrigues May 08 '19 at 19:42
  • @FilipeRodrigues: Did you try, er, inheriting the constructors? Of course, `C` would have to be default-constructible, which maybe defeats the purpose. – Davis Herring May 09 '19 at 00:07
  • @DavisHerring Even if there was a default constructor, if I normally inherited `B`'s constructor, `C` would have it's own copy of `A`, so there's be two copies of ´A´ in `D`, which is the problem virtual inheritance solves, but in this case what I want to do is make B not virtual inherit, so it instantiates it's base class, and then make C not instantiate it's base class, but use `B`'s one, similar to how in normal virtual inheritance `B` and `C` would use the `A` instance that `D` constructed, except I want `B` to construct it. – Filipe Rodrigues May 09 '19 at 00:31

0 Answers0