C++ 在没有虚拟继承的情况下解决钻石继承

C++ Solving Diamond Inheritance Without Virtual Inheritance

我有以下菱形 class 无法编译的结构:

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

我知道正常的解决方案是从 Base 虚拟继承;但是,我不允许更改 NotMineToTouch(或 Base)。还有其他解决方案吗?我可以随意更改 MyParentClassEvilDiamond;但是,EvilDiamond 必须继承自 MyParentClassNotMineToTouch,并且 MyParentClass 必须继承自 Base 而不能继承自 EvilDiamond.

我质疑以下论断:

EvilDiamond must inherit from MyParentClass and NotMineToTouch

您可能可以按照以下方式做一些事情(取决于您的架构):

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

你没有钻石,因为你没有使用虚拟继承。
你目前有一些 "Y" 继承(EvilDiamond 有 2 Base)。

在不改变你的 类 的情况下,你可以添加重载来指示编译器做什么:

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