2

I am trying to resolve a dreaded diamond problem with virtual class methods.

Let us first consider a multiple inheritance case with the peculiarity of a final virtual method. Since there is a final method one cannot declare an override method but has to use a using-declaration to specify which method should be used for the child class.

class Mother {
public:
    virtual void foo() final {}
};

class Father {
public:
    virtual void foo() {}
};

class Child: public Mother, public Father {
public:
    // void foo() {Mother::foo();} // This clashes with Mother::foo being final
    using Mother::foo;
};

The above code works as expected.

However, if we switch to a diamond-like structure with an abstract base class the same approach will no longer work.

class GrandParent {
public:
    virtual void foo() = 0;
};

class Mother: virtual public GrandParent{
public:
    virtual void foo() override final {};
};

class Father: virtual public GrandParent{
public:
    virtual void foo() override {};
};

class Child: public Mother, public Father {
    using Mother::foo;
};

Compiling the above code will raise the error: no unique final overrider for ‘virtual void GrandParent::foo()’ in ‘Child’.

Any ideas on how to solve this issue?

cxkoda
  • 153
  • 5
  • This might help; override is used to generate a compiler error if the child's class virtual function declaration does not match the base class declaration. The final keyword is typically used to mean that you can not derive from such a class. – Francis Cugler Jan 18 '19 at 16:22

1 Answers1

3

This is the language telling you your design is wrong. And it is. Inheritance reflects an "is-a" relationship. Not a "has-a".

The solution is to use composition instead of inheritance. I'd give an example but it is entirely unclear what you actually intend to accomplish and can't think of any sensible example.

rubenvb
  • 74,642
  • 33
  • 187
  • 332
  • 1
    Additional reading on this subject: [What is an example of the Liskov Substitution Principle?](https://stackoverflow.com/questions/56860/what-is-an-example-of-the-liskov-substitution-principle) – user4581301 Jan 18 '19 at 16:40
  • I would like to have a common base class (in this case GrandParent), which is used to define an abstract interface (with more methods than just foo). Subclasses (like Mother and Father) are then used to provide some (but not all) implementations of the said interface depending on specific assumptions. Some of those assumptions are so severe that part of the implementations should not be changed (final). The last child should then combine implementations. – cxkoda Jan 18 '19 at 16:42
  • 1
    @cxkoda That is your proposed solution shoe-horned into concepts you think apply, not the actual problem you are trying to solve without any assumption of what the solution looks like. – rubenvb Jan 18 '19 at 16:49
  • @rubenvb yes you a certainly right as I'm trying to fit my problem into a structure that, perhaps, is not very suitable. However, I don't understand why the first code works whereas the second does not. – cxkoda Jan 18 '19 at 18:01
  • @cxkoda 2 things 1) Virtual inheritance handles a common base class, `GrandParent`. It does not handle differences between the Parent classes. 2) [**class.virtual**](https://timsong-cpp.github.io/cppwp/n3337/class.virtual#2) states *if a virtual member function of a base class subobject has more than one final overrider the program is ill-formed.* This is what traps you. As soon as you have to disambiguate between the `foo`s of the parents, you have to break this rule. – user4581301 Jan 18 '19 at 20:27