Ich programmiere normalerweise in C #, versuche aber ein bisschen C ++ zu machen und versuche etwas, Schnittstellen in C ++ zu implementieren.
In C # würde ich so etwas tun:
%Vor%In C ++ habe ich es so implementiert:
%Vor%Das Problem ist, dass ich Foo nicht instantiieren kann, weil es abstrakt ist (implementiert DoSomething nicht). Ich weiß, dass ich DoSomething implementieren kann und nur die Methode auf Base anrufe, aber ich hatte gehofft, dass es einen besseren Weg dafür gibt. Ich habe andere Klassen, die von der Basis mit verschiedenen Datentypen erben, und ich habe andere Klassen, die von IDoubleDoSomething erben, die Base nicht verwenden.
Jede Hilfe wird geschätzt.
Wie andere bemerkt haben, sind die beiden Funktionen in den Basisklassen unabhängig voneinander (trotz des gleichen Namens und der gleichen Argumenttypen), da sie keine gemeinsame Basisklasse haben. Wenn Sie möchten, dass sie verwandt sind, müssen Sie ihnen eine gemeinsame Basisklasse geben.
Wenn Sie möchten, dass die Mehrfachvererbung ordnungsgemäß funktioniert, müssen Sie im Allgemeinen Ihre nicht privaten Basisklassen als virtual
deklarieren. Andernfalls, wenn Sie jemals gemeinsame Basisklassen haben (wie Sie oft für diese Art von Code benötigen), werden schlimme Dinge passieren.
Also können Sie Ihr Beispiel wie folgt aussehen lassen:
%Vor%Betrachten Sie den folgenden C ++ Code
%Vor% In C ++ können Sie Foo
verwenden, ohne dass ein IDoSomething1
und IDoSomething2
implementiert wird. Die zweite Methode MethodExpectsDosomething2
wird einfach nicht kompiliert, da Foo
nicht die Methode DoSomething2
hat.
In C # ist ein solches Konstrukt nicht möglich und zwingt Sie dazu, IDoSomething1
und IDoSomething2
interface zu haben und dies als Typbeschränkung .
Vielleicht müssen Sie sich Ihren Code ansehen und prüfen, ob solche Schnittstellen überhaupt benötigt werden.
Die Sache ist, Base::DoSomething
und IWhatever::DoSomething
sind zwei nicht verwandte Funktionen (auch wenn es keine reinen virtuellen Funktionen in diesem gibt, wäre es nicht möglich, DoSomething
für ein Foo
-Objekt aufzurufen, sowieso). Base
muss von IWhatever
erben, damit dies funktioniert.
Das heißt, fragen Sie sich, ob Sie das wirklich brauchen. Generische Programmierung mit Templates (und Konzepten, die wie Schnittstellen aussehen) finden Sie unter Boost.ConceptCheck ) ist in C ++ normalerweise eine bessere Lösung als der Runtime-Subtyp-Polymorphismus.
Sie könnten einen zweiten Template-Parameter an Base übergeben, die Schnittstelle, die implementiert werden soll:
%Vor% Für zusätzliche Bonuspunkte könntest du IDoubleDoSomething templatisieren (also zB IDoSomething<double>
) oder eine Traits-Klasse verwenden, um den Typ T auf die entsprechende Schnittstelle zu mappen.
In C ++ müssen reine virtuelle Funktionen immer in einer abgeleiteten Klasse außer Kraft gesetzt werden; Sie können keine Überschreibungen von anderen Basisklassen erben. Wenn Sie dynamischen Polymorphismus benötigen, glaube ich nicht, dass es eine sinnvolle Alternative zum Schreiben einer Funktion in Foo
gibt, die die Funktion Base
aufruft. Beachten Sie, dass die Funktion Base
nicht virtuell sein muss.
Je nachdem, wie Sie diese Klassen verwenden (insbesondere ob der reale Typ jeder Instanz der Schnittstelle zur Kompilierungszeit bekannt ist), können Sie möglicherweise statische Polymorphie verwenden, um Ihre bestimmte Implementierungsklasse in ihren Benutzer zu injizieren ein Vorlagenparameter; zum Beispiel:
%Vor%Sofern alles in Ordnung ist, sollte dies funktionieren.
%Vor%In Ihrem ursprünglichen Code hätte Foo 2 void DoSomething (double value) Methoden (1 ist abstrakt). Das wäre ein Basisteil und ein IDoubleDoSomething Teil. Foo :: Base und Foo :: IDoubleDoSomething. Sie könnten es versuchen, indem Sie IDoubleDoSomething.DoSomething () vorübergehend übergeben und implementieren.
Aber da Foo bereits "eine Basis" ist, hast du was du brauchst ohne IDoubleDoSomething.
Tags und Links c# c++ multiple-inheritance interface porting