Implementieren von Schnittstellen in C ++

8

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.

    
Clueless 03.01.2012, 16:50
quelle

6 Antworten

1

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%     
Chris Dodd 03.01.2012, 17:38
quelle
2

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.

    
parapura rajkumar 03.01.2012 17:07
quelle
2

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.

    
Cat Plus Plus 03.01.2012 17:12
quelle
2

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.

    
Alan Stokes 03.01.2012 17:22
quelle
2

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%     
Mike Seymour 03.01.2012 17:10
quelle
-1

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.

    
Todd Murray 03.01.2012 17:09
quelle