2

I encounter a scenario of nested interface declarations and implementation, and I am looking for a better solution. The two possible solutions I can think of are either have wrapper objects in implementation, or using diamond inheritance. I am not satisfy with the wrapper objects as if I have over ten methods in each interface then there will be a lot of wrapper methods in each level of implementation class. The diamond inheritance implementation is more concise but I am told to avoid using diamond inheritance whenever possible. Can anyone suggest an alternative better solution than the 2 in this question?

The wrapper object implementation is

class IA
{
public:
    virtual void MA() = 0;
};

class IB : public IA
{
public:
    virtual void MB() = 0;
};

class IC : public IB
{
public:
    virtual void MC() = 0;
};

class ID : public IC
{
public:
    virtual void MD() = 0;
};

// ------------------------

class ImplA : public IA
{
public:
    void MA() { /* do A */ }
};

class ImplB : public IB
{
public:
    void MA() { a.MA(); }
    void MB() { /* do B */ }
private:
    ImplA a;
};

class ImplC : public IC
{
public:
    void MA() { b.MA(); }
    void MB() { b.MB(); }
    void MC() { /* do C */ }
private:
    ImplB b;
};

class ImplD : public ID
{
public:
    void MA() { c.MA(); }
    void MB() { c.MB(); }
    void MC() { c.MC(); }
    void MD() { /* do D */ }
private:
    ImplC c;
};

The diamond inheritance examples is

class IA
{
public:
    virtual void MA() = 0;
};

class IB : public virtual IA
{
public:
    virtual void MB() = 0;
};

class IC : public virtual IB
{
public:
    virtual void MC() = 0;
};

class ID : public virtual IC
{
public:
    virtual void MD() = 0;
};

// ------------------------

class ImplA : public virtual IA
{
public:
    void MA() { /* do A */ }
};

class ImplB : public IB, public virtual ImplA
{
public:
    void MB() { /* do B */ }
};

class ImplC : public IC, public virtual ImplB
{
public:
    void MC() { /* do C */ }
};

class ImplD : public ID, public ImplC
{
public:
    void MD() { /* do D */ }
};
TobiMcNamobi
  • 4,687
  • 3
  • 33
  • 52
simon
  • 391
  • 1
  • 9

1 Answers1

0

If I'm facing complex design tasks where inheritance is strongly involved, then the CRTP comes to my mind. But I'm not sure if this will help you here. It depends a bit an the "meaning" of those interfaces, classes, and methods.

Which leads me to the question of "meaning" in relation to "design" in general. Two points are important here

  • Readability. Make it as simple and clear as possible.
  • Abstraction. The design should reflect that it is a model for some part in the real world.

Drawing your two solutions as UML (or even without that), you may see that the structure is very similar. ImplC for example has an instance of ImplB as a member or it has it as a parent. So this boils down to the question of composition vs inheritance.

Community
  • 1
  • 1
TobiMcNamobi
  • 4,687
  • 3
  • 33
  • 52
  • In the example of the question, the base class do not access the derived class methods, so the CRTP does not help. I had UML of the 2 designs and I understand they are very similar. The interfaces are the APIs of a library with the implementation classes forms the library. The client object always use interface pointer to access the library function. The interfaces can be seen as evolving versions of an API contract. The diamond inheritance was my initial design, but it was questioned in review. – simon Jun 01 '15 at 12:29