Hirsch Alter
Hirsch Alter

Reputation: 47

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.

Upvotes: 2

Views: 2541

Answers (2)

Jarod42
Jarod42

Reputation: 217235

You don't have diamond as you don't use virtual inheritance.
you have some "Y" inheritance currently (EvilDiamond has 2 Base).

Without changing your classes, you may add overloads to instruct compiler what to do:

void processBase (EvilDiamond* evil) {
    processBase(static_cast<NotMineToTouch*>(evil)); // Use NotMineToTouch::Base
    processBase(static_cast<MyParentClass*>(evil));  // Use MyParentClass::Base
}

Upvotes: 2

user4442671
user4442671

Reputation:

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_;}
};

Upvotes: 4

Related Questions