【问题标题】:C++ Solving Diamond Inheritance Without Virtual InheritanceC++ 解决没有虚拟继承的钻石继承问题
【发布时间】:2017-12-09 23:43:43
【问题描述】:

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

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

【问题讨论】:

  • 我只收到警告而不是错误。你能给我们你得到的实际编译器错误或发布重现问题的代码吗?顺便说一句,如果您不使用虚拟继承,它就不是钻石。虚拟继承是将两个基础合并为一个,如果您在图表中绘制菱形形状。
  • 我们在 Bases 和 MyParentClass 的其他地方调用了虚拟方法 getA()(在代码中我并不总是被允许更改)。可能不是钻石继承,但肯定是钻石问题(见标签上的说明)。当我在 EvilDiamond 上调用 getA() 时出现编译器错误:错误:对成员“getA”的请求不明确注意:候选者是:virtual int Base::getA() 注意:virtual int Base::getA()
  • 传递对象时不能转换为正确的类型吗?
  • Passer By - 我不能将一个对象转换为它不是的东西(因此我需要多重继承)。我认为没有理由强制转换——如果我的对象子类化了一个基类,我可以将它传递到需要该类指针的地方。这不是过载问题。
  • 以下代码会给出该错误void processEvilDiamond (EvilDiamond* n) { n->doSomething(); } 解决方案是指定您想要的:void processEvilDiamond (EvilDiamond* n) { n->MyParentClass::doSomething(); }

标签: c++ c++11 multiple-inheritance diamond-problem


【解决方案1】:

我对以下断言提出质疑:

EvilDiamond 必须继承自 MyParentClass 和 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_;}
};

【讨论】:

  • 编辑了原帖。我有其他方法可以接受需要传递 EvilDiamond 的 Base。
【解决方案2】:

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-05
    • 2011-02-09
    • 1970-01-01
    • 2020-01-01
    • 2012-04-19
    • 1970-01-01
    相关资源
    最近更新 更多