0

I have a kind of "triangle inheritance" problem, if such a thing exists. Basically, I have an abstract base class the defines an interface, and a policy class that defines the implementation to part of that interface, like so:

class System
{
public:
    Interface() = default;
    virtual ~Interface() {}

    virtual void doSomething() = 0;
    virtual bool somethingDone() const = 0;

    virtual int trait1() const = 0;
    virtual bool trait2() const = 0;
};

class SomethingImplementation
{
public:
    SomethingImplementation() = default;
    void doSomething() { (void)0; }
    bool somethingDone() { return true; }
};

And then I have several implementations of the interface for different cases. In some cases, I want to use the simple implementation, and in others I want to customize them

class SystemA : public System, public SomethingImplementation {/*...*/};
class SystemB : public System, public SomethingImplementation {/*...*/};
class SystemC : public System, { /* with a custom implementation ... */ };

What I can't figure out is what the details of class SystemA or SystemB might be to make the implementation work

http://cpp.sh/73r5

Solution 1

using statements, don't seem to do anything in this case.

http://cpp.sh/2nhki

59:13: error: cannot declare variable 'a' to be of abstract type 'SystemA'
22:7: note:   because the following virtual functions are pure within 'SystemA':
6:18: note:     virtual void System::doSomething()
7:18: note:     virtual bool System::somethingDone() const
60:13: error: cannot declare variable 'b' to be of abstract type 'SystemB'
31:7: note:   because the following virtual functions are pure within 'SystemB':
6:18: note:     virtual void System::doSomething()
7:18: note:     virtual bool System::somethingDone() const
63:38: error: invalid new-expression of abstract class type 'SystemA'

Solution 2

Add an extra interface class. Create a SomethingInterface class and inherit both Interface and SomethingImplementation from SomethingInterface. This turns the problem into a regular "diamond inheritance" problem, but I still can't seem to get the compiler to do what I want.

http://cpp.sh/3dxab

What is the way to use the implementation from another class for a virtual method of a parent class?

Stefan Sullivan
  • 1,517
  • 2
  • 10
  • 9

2 Answers2

0

I believe you want to do something like this.

// The interface.
class IInterface
{
public:
    virtual ~IInterface() {}
    virtual void method1() = 0;
    virtual void method2() = 0;
};

// A partial, abstract implementation of interface.
// This base class implements method1 but leaves method2 unimplemented,
// which means this class cannot be instantiated.
class PartialImplementation : public IInterface
{
public:
    virtual void method1() {}
};

// Full implementation that uses the partial implementation above.
// method1's implementation is from the base class.
// method2's implementation is in this class.
// Because all methods are implemented (directly or inherited), this class can be instantiated.
class FullImplementation1 : public PartialImplementation
{
public:
    void method2() {}
};

// Full implementation that uses the partial implementation above.
// method1's implementation is in this class (overrides base implementation).
// method2's implementation is in this class.
// Because all methods are implemented (directly), this class can be instantiated.
class FullImplementation2 : public PartialImplementation
{
public:
    void method1() {}
    void method2() {}
};

// Full implementation that DOES NOT use the partial implementation above.
// method1's implementation is in this class.
// method2's implementation is in this class.
// Because all methods are implemented (directly), this class can be instantiated.
class FullImplementation3 : public IInterface
{
public:
    void method1() {}
    void method2() {}
};

int main()
{
    FullImplementation1 i1; // OK
    FullImplementation2 i2; // OK
    FullImplementation3 i3; // OK

    IInterface* p1 = new FullImplementation1(); // OK
    delete p1; // OK

    IInterface* p2 = new FullImplementation2(); // OK
    delete p2; // OK

    IInterface* p3 = new FullImplementation3(); // OK
    delete p3; // OK

    return 0;
}
Michael Gunter
  • 12,528
  • 1
  • 24
  • 58
  • Note that you could also have `PartialImplementation` which does not implement the interface. Then you would have to explicitly implement the interface on the full implementations, and the implementation of those methods could call the methods on the base partial implementation. – Michael Gunter Feb 09 '17 at 19:56
  • Also: As mentioned by other commenters, you don't have a diamond inheritance here and you don't need virtual inheritance. If you have _multiple_ partial implementations that you're trying to use as bases to a single full implementation, then you might use virtual inheritance to produce a diamond inheritance. – Michael Gunter Feb 09 '17 at 20:04
0

Every example I've seen of diamond inheritance was from bad design because of a misunderstanding of the IS-A and HAS-A relationships. Don't inherit to use an implementation, inherit to provide an implementation (e.g. inherit to implement).

SystemA should inherit from System and have a SomethingImplementation as a member whose methods it calls.

You might also look into mixins.

Rob K
  • 8,757
  • 2
  • 32
  • 36
  • Thanks for the concise description. That's exactly what I was doing. I looked into mixins and it seemed like it wasn't quite what I wanted either. I guess it's time for me to buy Alexandrescu's book now – Stefan Sullivan Feb 09 '17 at 20:07