Virtuelle Vererbung und gefürchteter Diamant

9

Ich habe eine harte Zeit mit einem gefürchteten Diamantenproblem. Zur Erinnerung, hier ist die klassische Klassenhierarchie dieses Problems:

%Vor%

Um es zu lösen, besteht die Standardlösung darin, dass C1 und C2 virtuelle Vererbung verwenden, um von B zu übernehmen.

Mein Problem ist, dass B und C1 von einem SDK stammen, das ich nicht ändern kann. Beispiel unten, wo ich SubClassB nicht virtuell von Basis erben kann. Klassen: PureVirtualBase, Base und SubClassB stammen aus dem SDK, das ich verwende. Ich kann sie nicht ändern. SubClassA und Leaf sind meine benutzerdefinierten Klassen. Ich kann sie ändern.

%Vor%

In einer solchen Situation, in der SubClassB nicht geändert werden kann, wird die virtuelle Vererbung von Basis verwendet. Wie sollte das so aussehen:

  • Die Leaf Instanz enthält nur eine Basis
  • Vermeiden Sie Mehrdeutigkeiten, wenn Sie versuchen, auf Funktionen zuzugreifen, die in PureVirtualBase rein virtuell definiert und in Base implementiert sind
%Vor%
  • Wenn ich den Aufruf von f_PurevirtualBase kommentiere, kompiliert er, aber ich habe eine warnte das virtuelle Basis 'Base' ist aufgrund von Mehrdeutigkeit nicht in 'Leaf' erreichbar. Wenn ich diesen Aufruf auskommentiere, erhalte ich folgende Fehlermeldung: Anfrage für ein Mitglied 'f_PureVirtualBase' ist nicht eindeutig
  • Wenn ich diesen Aufruf mit dem Klassennamen voranstelle (myleaf.SubClassA :: f_PureVirtualBase () dann funktioniert es, aber sowas ist offensichtlich falsch, da es 2 Basis im Blatt gibt Objekt).

Irgendein Hinweis?

Weitere Informationen zum Beantworten von Kommentaren

Meine Zielarchitektur ist etwas komplexer als die Probe, die ich in der ursprünglichen Frage bereitgestellt habe:

%Vor%

LeafOne: erbt von SubClassA und SubClassB (SDK)

LeafTwo: erbt von SubClassA und SubClassC (SDK)

LeafThree: erbt von SubClassA und SubClassD (SDK)

SubClassA ist mein eigener privater Code. Es bietet benutzerdefinierte Funktionen. Es sollte von SDK-Methoden wie eine Base-Instanz behandelt werden können. Diese Klasse wird nicht instanziiert, aber sie ist hier, um LeafOne, LeafTwo und LeafThree gleichzeitig behandeln zu können.

    
Marc 05.04.2012, 10:39
quelle

2 Antworten

4

Dies weist auf ein Problem mit Ihrem Design hin, für das die einfachste Antwort ist, den Diamanten zu vermeiden. Ihre Auswahl an Namen für den Beispielcode ist schlimm genug, um es schwer zu machen, darüber nachzudenken, was Sie eigentlich tun möchten, aber überlegen Sie auf jeden Fall, ob Sie von beiden Eltern erben müssen und ob das macht Sinn.

Vererbung ist eines der am meisten missbrauchten Konstrukte in OO-Sprachen, es löst zwar ein Problem, wird aber als golden verwendet hammer überall sonst. Viele Male, was Sie in der Hand haben, ist ein Schraube , kein Nagel und das richtige Werkzeug ist kein Hammer.

    
David Rodríguez - dribeas 05.04.2012, 12:09
quelle
1

Wenn Sie wirklich an diesen Designbeschränkungen festhalten, würde ich definitiv versuchen, von B direkt mit einer Klasse zu untergliedern, die C1 und C2 als zusammengesetzte Komponenten verwendet. Leider erfordert das manuelle Spiegeln der Benutzeroberfläche (hoffentlich ist es klein oder Sie können es auf das, was Sie benötigen, beschränken) und Proxy bis zu den Unterkomponenten. Es ist nicht schön, aber wenn Sie nicht etwas anderes auf dem Design durchsetzen können, dann haben Sie nicht wirklich viel Auswahl.

Ein Nachteil ist natürlich, dass Sie nicht die Typidentität haben, nach der Sie suchen (die Unterklasse wird nicht "isa" von C1 oder C2 erfüllen), was ausreichen könnte, um diesen Ansatz aus dem Wasser zu blasen.

Es ist nicht schön. Aber ich erwarte, dass es angesichts Ihrer Einschränkungen die "schlechteste" Lösung sein könnte.

    
Michael Wilson 05.04.2012 13:34
quelle