2

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.

5
  • I only get a warning not an error. Can you give us the actual compiler error you are getting or post code that reproduces the problem. BTW it isn't a diamond if you don't use virtual inheritance. Virtual inheritance is what merges the two bases into one creating the diamond shape if you draw it in a diagram. Commented Jul 6, 2017 at 6:13
  • We call the virtual method getA() in other places on Bases and MyParentClass (in code I am not always allowed to change). It may not be diamond inheritance, but it is certainly the diamond problem (see the description on the tag). Compiler error when I call getA() on an EvilDiamond: error: request for member 'getA' is ambiguous note: candidates are: virtual int Base::getA() note: virtual int Base::getA() Commented Jul 6, 2017 at 6:28
  • Can you not cast to the right type when you pass the object? Commented Jul 6, 2017 at 7:38
  • Passer By - I cannot cast an object to something it is not (hence why I need to multiple inherit). I see no reason to cast - if my object subclasses a base class, I can pass it where a pointer of that class is called for. This is not an overload issue. Commented Jul 6, 2017 at 8:12
  • The following code would give that error void processEvilDiamond (EvilDiamond* n) { n->doSomething(); } the solution is to specify which one you want: void processEvilDiamond (EvilDiamond* n) { n->MyParentClass::doSomething(); } Commented Jul 6, 2017 at 12:39

2 Answers 2

4

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_;}
};
Sign up to request clarification or add additional context in comments.

1 Comment

Edited the original post. I have other methods that accept a Base where I need to pass an EvilDiamond.
2

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
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.