Search code examples
c++c++11multiple-inheritancediamond-problem

C++ Solving Diamond Inheritance Without Virtual Inheritance


I have the following diamond class structure that does not compile:

class Base{
  int a;
public:
  virtual void doSomething();
};

class NotMineToTouch : public Base {};

class MyParentClass : public Base {};

class EvilDiamond : public NotMineToTouch, public MyParentClass {};

// I need these methods (that I cannot necessarily edit) to work for an EvilDiamond
void processBase (Base* b) { b->doSomething; /*...*/} // Cannot edit

void processParent (MyParentClass* p) { p->doSomething; /*...*/} // Can edit

void processNotMine (NotMineToTouch* n) { n->doSomething; /*...*/} // Cannot edit

I know the normal solution is to inherit virtually from Base; however, I am not allowed to change NotMineToTouch (or Base). Is there another solution? I am allowed to change MyParentClass and EvilDiamond at my pleasure; however, EvilDiamond must inherit from MyParentClass and NotMineToTouch, and MyParentClass must inherit from Base and may not inherit from EvilDiamond.


Solution

  • I challenge the following assertion:

    EvilDiamond must inherit from MyParentClass and NotMineToTouch

    You can probably do something along these lines (depending on your architecture):

    class EvilDiamond;
    
    class NotMineToTouchImpl : public NotMineToTouch {
      EvilDiamond* tgt_;
    public:
      NotMineToTouchImpl(EvilDiamond* tgt) : tgt_(tgt) {}
    
      ... implement NotMineToTouch here, using tgt_ where you would have used this
    };
    
    class MyParentClassImpl : public MyParentClass {
      EvilDiamond* tgt_;
    public:
      MyParentClassImpl(EvilDiamond* tgt) : tgt_(tgt) {}
    
      ... implement Base here, using tgt_ where you would have used this
    };
    
    class EvilDiamond {
      friend class NotMineToTouchImpl;
      friend class MyParentClassImpl;
    
      // Creating permanent instances of the API classes 
      // may or may not be appropriate in your case.
      NotMineToTouchImpl nmti_;
      MyParentClassImpl pci_;
    public:
      EvilDiamond () : nmti_(this), pci_(this) {}
    
      NotMineToTouchImpl* getAsNotMineToTOuch() {return &nmti_;}
      MyParentClassImpl * getAsParentClass() {return &pci_;}
    };