2017-07-06 6 views
3

ich folgende Diamant Klassenstruktur haben, die nicht kompiliert:C++ Lösung von Diamant Vererbung ohne virtuelle Vererbung

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 

ich die normale Lösung wissen praktisch von Base zu erben ist; Ich darf jedoch nicht NotMineToTouch (oder Base) ändern. Gibt es eine andere Lösung? Ich bin berechtigt, MyParentClass und EvilDiamond zu meinem Vergnügen zu ändern; EvilDiamond muss jedoch von MyParentClass und NotMineToTouch erben, und MyParentClass muss von Base erben und darf nicht von EvilDiamond erben.

+0

Ich erhalte kein Fehler eine Warnung nur. Können Sie uns den tatsächlichen Compilerfehler geben, den Sie erhalten, oder den Code eingeben, der das Problem reproduziert? Übrigens ist es kein Diamant, wenn Sie keine virtuelle Vererbung verwenden. Die virtuelle Vererbung verbindet die beiden Basen zu einer einzigen, die die Rautenform erzeugt, wenn Sie sie in einem Diagramm zeichnen. – Eelke

+0

Wir nennen die virtuelle Methode getA() an anderen Stellen auf Bases und MyParentClass (im Code kann ich nicht immer ändern). Es ist vielleicht keine Diamantenvererbung, aber es ist sicherlich das Diamantproblem (siehe die Beschreibung auf dem Etikett). Compiler Fehler beim Aufruf von getA() auf einem EvilDiamond: Fehler: Anfrage für Mitglied 'getA' ist mehrdeutig Hinweis: Kandidaten sind: virtual int Base :: getA() Hinweis: virtual int Base :: getA() –

+0

Kann Sie nicht zum richtigen Typ, wenn Sie das Objekt übergeben? –

Antwort

3

Ich fordere die folgende Behauptung:

EvilDiamond must inherit from MyParentClass and NotMineToTouch

Sie wahrscheinlich etwas in dieser Richtung (je nach Architektur) tun können:

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

Editierte den ursprünglichen Beitrag. Ich habe andere Methoden, die eine Basis akzeptieren, wo ich einen EvilDiamond bestehen muss. –

2

Sie haben keine Diamanten, wie Sie nicht tun Verwenden Sie virtuelle Vererbung.
Sie haben einige "Y" Vererbung derzeit (EvilDiamond hat 2 Base).

Ohne Ihre Klassen zu ändern, können Sie Überlastungen hinzufügen Compiler anweisen, was zu tun ist:

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