2008-10-31 14 views
22

Ich habe eine abstrakte Basisklasse, die als Schnittstelle fungiert.Mehrfachvererbung von zwei abgeleiteten Klassen

Ich habe zwei "Mengen" von abgeleiteten Klassen, die die Hälfte der abstrakten Klasse implementieren. (ein "set" definiert die abstrakten virtuellen Methoden in Bezug auf die Initialisierung, der andere "set" definiert diejenigen im Zusammenhang mit der tatsächlichen "Arbeit".)

Ich habe dann abgeleitete Klassen, die Mehrfachvererbung verwenden, um vollständig definierte Klassen (und fügt nichts hinzu).

Also: (schlecht Pseudo-Code)

class AbsBase { 
    virtual void init() = 0; 
    virtual void work() = 0; 
} 

class AbsInit : public AbsBase { 
    void init() { do_this(); } 
    // work() still abs 
} 

class AbsWork : public AbsBase { 
    void work() { do_this(); } 
    // init() still abs 
} 

class NotAbsTotal : public AbsInit, public AbsWork { 
    // Nothing, both should be defined 
} 

Zunächst einmal kann ich dies tun? Kann ich von zwei Klassen erben, die beide von derselben Base abgeleitet sind? (Ich hoffe es).

Hier ist das "echte Problem", obwohl (ich habe ein wenig darüber gelogen, um das Beispiel zu vereinfachen).

Was ich wirklich nicht abstrakt Accessoren Methoden der Basisklasse hinzufügen gegangen und getan:

class AbsBase { 
public: 
    void init() { init_impl(); } 
    void work() { work_impl(); } 

private: 
    virtual void init_impl() = 0; 
    virtual void work_impl() = 0; 
} 

Weil ein gemeinsames Idiom alle virtuellen Methoden privat zu machen.

Leider erben jetzt sowohl AbsInit, als auch AbsWork diese Methoden, und so erbt NotAbsTotal "zwei von jedem" (ich weiß, dass ich schlachten kann, was wirklich zur Kompilierzeit geschieht).

Wie auch immer, g ++ beschwert sich: "Anfrage für Member init() ist mehrdeutig" beim Versuch, die Klasse zu verwenden.

Ich nehme an, dass, hätte ich meine AbsBase-Klasse als reine Schnittstelle verwendet, dies vermieden worden wäre (vorausgesetzt, das obere Beispiel ist gültig).

Also: - Bin ich mit meiner Implementierung weg? - Ist dies eine Einschränkung des Idioms, virtuelle Methoden privat zu machen? - Wie referenziere ich meinen Code, um zu tun, was ich will? (Geben Sie eine gemeinsame Schnittstelle, sondern ermöglichen eine Möglichkeit, Implementierungen auszulagern für „Sets“ von Elementfunktionen)

Edit:

Scheint Ich bin nicht der erste: http://en.wikipedia.org/wiki/Diamond_problem

scheint virtuelle Vererbung ist die Lösung hier. Ich habe schon früher von virtueller Vererbung gehört, aber ich habe meinen Kopf nicht darum herumgelegt. Ich bin immer noch offen für Vorschläge.

Antwort

33

Es sieht so aus, als ob Sie virtuelle Vererbung durchführen möchten. Ob das erweist sich tatsächlich eine gute Idee ist eine andere Frage, aber hier ist, wie Sie es tun:


class AbsBase {...}; 
class AbsInit: public virtual AbsBase {...}; 
class AbsWork: public virtual AbsBase {...}; 
class NotAbsTotal: public AbsInit, public AbsWork {...}; 

Grundsätzlich ist die standardmäßig nicht-virtuellen Mehrfachvererbung eine Kopie jeder Basisklasse in der enthalten wird abgeleitete Klasse und schließt alle ihre Methoden ein. Das ist der Grund, warum Sie zwei Kopien von AbsBase haben - und der Grund dafür, dass Ihre Methoden nicht eindeutig sind, ist, dass beide Methodengruppen geladen sind, so dass C++ nicht wissen kann, auf welche Kopie zugegriffen werden soll!

Die virtuelle Vererbung verdichtet alle Verweise auf eine virtuelle Basisklasse in eine Datenstruktur. Dies sollte die Methoden aus der Basisklasse wieder eindeutig machen. Beachten Sie jedoch Folgendes: Wenn in den beiden Zwischenklassen zusätzliche Daten vorhanden sind, kann der zusätzliche Laufzeitaufwand gering sein, damit der Code die gemeinsame virtuelle Basisklasse finden kann.

+0

Warum sagst du das? Welche Auswirkungen hat die virtuelle Vererbung neben der Syntaxkomplexität? – mmocny

+0

Die Konvertierung eines Basiszeigers in eine abgeleitete Klasse umfasst normalerweise Zeigeranpassungen unter Verwendung einer dynamischen Nachschlagetabelle. Diese zusätzliche Indirektion führt Kosten für die Umwandlung von der Basis in die abgeleitete Menge ein. Beim Aufruf einer virtuellen Methode liegt dieser Overhead im Anrufrauschen. –

1

Es kann getan werden, obwohl es die meisten Schauer gibt.

Sie müssen „virtuelle Vererbung“ verwenden, die Syntax für die ist so etwas wie

class AbsInit: public virtual AbsBase {...}; 
class AbsWork: public virtual AbsBase {...}; 
class NotAbsTotal: public AbsInit, public AbsWork {...}; 

Dann müssen Sie angeben, welche Funktion Sie verwenden möchten:

NotAbsTotal::work() 
{ 
    AbsInit::work_impl(); 
} 

(AKTUALISIERT mit korrektem Syntax)

1

Sie müssen die Vererbung als virtuelle zu erklären:

struct AbsBase { 
      virtual void init() = 0; 
      virtual void work() = 0; 
}; 

struct AbsInit : virtual public AbsBase { 
      void init() { } 
}; 

struct AbsWork : virtual public AbsBase { 
      void work() { } 
}; 

struct NotAbsTotal : virtual public AbsInit, virtual public AbsWork { 
}; 

void f(NotAbsTotal *p) 
{ 
     p->init(); 
} 

NotAbsTotal x; 
+0

Dieses gut funktioniert, auch mit meinem nicht-virtuellen öffentlichen Methoden. Allerdings muss ich versuchen zu sehen, was passiert, wenn ein Zeiger des Basistyps auf ein Objekt des abgeleiteten Typs verwendet wird, um sicherzustellen, dass die virtuelle Vererbung wie das Überladen virtueller Funktionen funktioniert :) – mmocny

+0

Bei der Konvertierung von einer virtuellen Basis in eine abgeleitete Klasse Sie müssen immer dynamic_cast <> verwenden, was wiederum erfordert, dass eine virtuelle Methode in der virtuellen Datenbank definiert wird.Die einfache Verwendung einer virtuellen Basis sollte keine Probleme verursachen - sie wird polymorph den Zugriff auf die abgeleitete Klasse ermöglichen. –

0

Sie müssen anfangen zu denken, was Sie hier zu modellieren versuchen.

Öffentliche Vererbung sollte immer nur verwendet werden, um eine "isa" -Beziehung zu modellieren, z.B. ein Hund ist ein Tier, ein Quadrat ist eine Form, etc.

Schauen Sie sich Scott Meyers Buch Effective C++ für einen exzellenten Aufsatz an, in dem die verschiedenen Aspekte des OO-Designs immer nur so interpretiert werden sollten.

Edit: Ich vergaß zu sagen, dass, während die Antworten soweit technisch korrekt sind, ich glaube nicht, dass einer von ihnen die Probleme von dem, was Sie versuchen zu modellieren adressieren und das ist der Kern Ihres Problems!

HTH

prost,

Rob

0

fand ich ein gutes und einfaches Beispiel auf untenstehenden Link. Der Artikel erklärt mit einem Beispielprogramm für die Berechnung der Fläche und des Umfangs eines Rechtecks. Sie können es überprüfen .. berechen

Multilevel Inheritance ist eine Vererbungshierarchie, in der eine abgeleitete Klasse von mehreren Basisklassen erbt. Lesen Sie mehr ..

http://www.mobihackman.in/2013/09/multiple-inheritance-example.html