Interfaces und abstrakte Klassen in C++



  • Hi zusammen,

    ich las bereits, dass es Interfaces in C++ aufgrund von Mehrfachvererbung nicht gäbe, kann man das so sehen? Gibt es diesbezüglich keinen "Ersatz"?

    Wird in C++ eine abstrakte Klasse bezeichnet, die entweder nur abstrakte(virtual) Methoden hat, oder nicht-abstrakte und abstrakte(virtual) implementiert?

    Irre ich mich da in meiner Auffassung?


  • Administrator

    Fenixx schrieb:

    ich las bereits, dass es Interfaces in C++ aufgrund von Mehrfachvererbung nicht gäbe, kann man das so sehen? Gibt es diesbezüglich keinen "Ersatz"?

    In C++ gibt es keine Java-Interfaces. Allerdings hat Java da eher einen schlechten Namen verwendet. Wieso sollte ein Interface nicht auch eine Default-Implementation bieten?

    In C++ kannst du auch das Java-Interface Prinzip umsetzen, du hast aber noch viel mehr Möglichkeiten. Einen Java-Interface Ersatz ist überhaupt nicht nötig.

    Fenixx schrieb:

    Wird in C++ eine abstrakte Klasse bezeichnet, die entweder nur abstrakte(virtual) Methoden hat, oder nicht-abstrakte und abstrakte(virtual) implementiert?

    In C++ ist eine Klasse abstrakt, sobald mindestens eine Methode abstrakt ist.

    Grüssli



  • Dravere schrieb:

    Wieso sollte ein Interface nicht auch eine Default-Implementation bieten?

    Eine nicht ganz so einfache Frage. Ich würde sagen, dass Java da schärfer trennt. Wenn ich zu Beginn noch nichts genaueres über die Implementation weiß -> Interfaces. Kann ich schon Teile implementieren, aber noch nicht alles -> abstrakte Klassen.

    Wie sähe dann ein Java-Interface in C++ aus? Blauäugig würde ich sagen, dass ne Header-Datei dem schon sehr nahe kommt. Ist das vielleicht solch ein Lösungsansatz?
    In C++ kann man doch eine abstrakte Klasse instanziieren oder?
    Folgendes hat nämlich funktioniert:
    Vogel.h:

    #ifndef VOGEL_H_INCLUDED
    #define VOGEL_H_INCLUDED
    class Vogel
    {
    	public:
    		virtual void fliege();
    };
    #endif
    

    Implementierung in ner cpp-Datei und dann die Instanziierung:

    int main()
        {
          Vogel vogel;
          vogel.fliege();
    }
    

    Oder irre ich mich da?



  • Die Frage ist doch, warum wird hier so viel über Java geschrieben? C++ ist nicht Java und auch nicht dazu gedacht Java code zu implementieren. Wenn du ein Interface willst, dann nimm eine Pur-Abstrakte Klasse (alles virtuell und keine implementierung).



  • Um es mal so auszudrücken:

    Ich hab ursprünglich Java gelernt und versuche mich in C++ zurechtzufinden. Da versuche ich die Konzepte wie z.B. Interfaces und abstrakte Klassen wiederzufinden. Für den Einstieg ist es denk ich ganz gut.

    Ich weiß, dass Java nicht C++ ist und umgekehrt.
    Allerdings fehlt mir die klare Abgrenzung zwischen den beiden Konzepten. Hier ein Beispiel:
    http://tutorial.schornboeck.net/pure_virtual.htm
    "BaseFormat ist eine abstrakte Klasse und dient uns als Interface". Dann frage ich mich, was BaseFormat jetzt nun ist. Ein Interface oder eine abstrakte Klasse? Die genannte Aussage ist für mich etwas schwammig, da ich von Java eine klare Abgrenzung gewohnt bin.



  • Es gibt keinen Unterschied! Die Frage ist, wie du es benutzt.
    Für dich als Java-Jünger wären nur pure-abstract-Klassen Interfaces.
    Für mich wären auch solche Klassen eine Schnittstelle, die für bestimmte Dinge eine default-implementation vorhanden ist oder supporter-Routinen. Der Begriff ist in C++ halt schwammig, weil er keinem fest definierten Schlüsselwort entspricht.



  • Damit ich es richtig versteh:

    Ein Interface in Java ist in C++: Eine Klasse, die nur Methodenrümpfe hat, die alle den Modifier virtual haben. Keine Implementierung auch nur einer Methode wird dabei vorgenommen.

    Eine abstrakte Klasse in Java ist in C++: Eine Klasse, die nur Methodenrümpfe hat, von der mindestens ein den Modifier virtual hat. Mindestens eine Methode wird implementiert.
    Im Gegensatz zu Java können dann abstrakte Klassen in C++ instanziiert werden.

    Kann man das so sagen?

    Tut mir leid wegen den Vergleichen, aber ich suche nach einer für mich verständlichen und korrekten Definition. 😃



  • Eine abstrakte Klasse in C++:

    class IVogel
    {
       virtual bool fly() = 0;
    };
    

    Eine Instanzierung von IVogel ist somit nicht möglich. JEde ableitende Klasse muss bool fly() implementieren.
    edit:
    NUR virtual reicht nicht, da virtual lediglich einen Virtual File Table Pointer anlegt, der es ermöglich die Methode zu überschreiben in einer abgeleiteten KLasse. Das "=0" bewirkt, dass fly() nicht angelegt wird, sondern auf NULL zeigt. Und damit ist die Klasse ungültig. Mit meinen Laienhaften Worten erklärt.
    HTH
    rya.



  • Klassen die nur eine einzige pur-virtuelle Methode enthalten können in C++ nicht instantiiert werden.

    PS: Siehe Scorcher 😉


  • Administrator

    Fenixx schrieb:

    Eine nicht ganz so einfache Frage. Ich würde sagen, dass Java da schärfer trennt. Wenn ich zu Beginn noch nichts genaueres über die Implementation weiß -> Interfaces. Kann ich schon Teile implementieren, aber noch nicht alles -> abstrakte Klassen.

    Nein, Java probiert so die Mehrfachvererbung einfach zu implementieren. Ich habe einige Zweifel, dass es den Java-Leuten ursprünglich um eine schärfere Trennung ging. Denn schlussendlich ist die Trennung nicht scharf, sondern eher mühsam.

    In C++ stellt jede Klasse eine Schnittstelle dar. Und das ist ja auch das Normalste, da jede Klasse eine Schnittstelle hat. Deshalb gibt es in C++ keine solche Trennung, da sie eigentlich gar nicht existiert.

    Fenixx schrieb:

    Wie sähe dann ein Java-Interface in C++ aus? Blauäugig würde ich sagen, dass ne Header-Datei dem schon sehr nahe kommt. Ist das vielleicht solch ein Lösungsansatz?

    Eine Header-Datei hat nichts mit Interface oder nicht Interface zu tun. Wenn du in C++ ein Java-Interface haben willst, dann mach alle Funktionen in der Klasse "pure virtual".

    Fenixx schrieb:

    In C++ kann man doch eine abstrakte Klasse instanziieren oder?
    Folgendes hat nämlich funktioniert:
    ...

    Abstrakte Klassen können nicht instanziiert werden. Dein Beispiel ist keine abstrakte Klasse.

    Grüssli



  • Dann verstehe ich folgendes nicht. Angenommen es liegt folgender Code vor:
    Die Definition:
    Vogel.h:

    #ifndef VOGEL_H_INCLUDED
    #define VOGEL_H_INCLUDED
    class Vogel
    {
    	public:
    		virtual void fliege();
    };
    #endif
    

    Die Implementation:
    Vogel.cpp:

    #include "Vogel.h"
    #include <iostream>
    void Vogel::fliege()
    {
    	printf("Der Vogel fliegt!");
    }
    

    Die Verwendung:

    int main()
        {
          Vogel vogel;
          vogel.fliege();
    }
    

    In diesem Fall lässt sich der Vogel instanziieren. Irgendwas verwirrt mich gerade



  • Noch ein Zusatz:
    Was möglich ist, ist einen Zeiger auf das Objekt zu haben. Allerdings muss der "Inhalt" des Zeigers die Implementation sein.
    Hier ein Beispiel für dich:

    // IVogel.hpp:
    class IVogel
    {
    public:
       virtual bool fly() = 0;
       virtual void cry() = 0;
    };
    
    // VogelImpl.hpp:
    class Chicken: public IVogel
    {
    public:
       virtual bool fly();
       virtual void cry();
    };
    
    // VogelImpl.cpp:
    
    bool Chicken::fly() 
    { return true; }
    
    void Chicken::cry()
    {  std::cout << "Pooock, Pock Pock!" << std::endl; }
    

    Das Problem ist nun die Instanzierung. Sowas kann man mit einer Factory-Klasse oder Funktion machen, ich nehm mal die Funktion, das ist weniger zu tippen :P.

    IVogel* ChickenFactory()
    {
      return new Chicken();
    }
    

    Somit weiss der User der API nichts von Chicken und verwendet nur IVogel. So eine Technik ist wunderbar für X-Platform Programming, da man so immer das gleiche Interface verwendet und Platformspezifische Member ausgeblendet werden.

    edit:
    Du hast dazwischengepostet 😃

    n diesem Fall lässt sich der Vogel instanziieren. Irgendwas verwirrt mich gerade

    Deine Klasse ist nicht abstrakt, lediglich der Member ist virtuell. Lies meinen Post bitte nochmal ganz :).
    rya.



  • class Vogel {
        virtual void fliege() = 0;
        virtual void lande() { /* default impl */ }
    };
    

    Vogel ließe sich nicht instantiieren.


  • Administrator

    Fenixx schrieb:

    In diesem Fall lässt sich der Vogel instanziieren. Irgendwas verwirrt mich gerade

    Die Klasse ist auch nicht abstrakt *sich wiederholt*
    Du solltest vielleicht nachschlagen was "pure virtual" heisst.

    class Vogel
    {
      virtual void fliege() = 0;
      // das = 0 bedeutet pure virtual. In der Klasse Vogel
      // existiert keine Definition von fliege.
    };
    

    Grüssli



  • Sorry, eure Texte konnte ich erst jetzt lesen.
    Ist dann IVogel eine Header- oder eine cpp-Datei? Rine cpp-Datei braucht doch eine Header-Datei oder?



  • Nein.
    Header-Dateien werden sozusagen cut&paste per #include in die Dateien eingefügt. Das ist alles... Sie werden in keinster weise speziell behandelt.



  • Fenixx schrieb:

    Sorry, eure Texte konnte ich erst jetzt lesen.
    Ist dann IVogel eine Header- oder eine cpp-Datei? Eine cpp-Datei braucht doch eine Header-Datei oder?

    *.hpp ist ein Header. Aber eine .cpp braucht nicht zwangsläufig einen Header. Allgemein definiert man halt die Funktionen aus einer .cpp in einer .hpp oder .h und man definiert Klassen in einer .hpp oder .h und implementiert sie in einer .cpp. Man kann eine Klasse aber auch "inline" in einer .hpp oder .h ausschreiben, sprich implementieren.
    Das mache ich bei kleinen Klassen, die nur versch. Member und Setter/Getter haben um einfache Daten zu kapseln. DAfür brauchts keine .cpp :).
    Beispiel:

    class MySimpleData
    {
    private:
       int a;
       float b;
    
    public: 
       int a() const { return a; }
       float b() const { return b; }
    
       setA(int _a) { a = _a; }
       setB(float _b) { b = _b; }
    };
    

    Das ist genauso erlaubt. Das ist nicht so strikt wie in Java.
    rya.



  • Es verwirrt mich nur deswegen, weil in meinen Augen Header-Dateien in gewisser Weise auch eine Klassendefinition, wie die eines Interfaces darstellen.
    Für IVogel habe ich demnach keine Header-Datei, sondern nur eine Cpp-Datei. Ist das so richtig?


  • Administrator

    @Fenixx,
    Wie kommst du jetzt auf *.cpp und *.hpp Dateien? Das hat rein gar nichts mit abstrakt, interface oder sonst was zu tun in diesem Zusammenhang.

    Ganz ehrlich, ich habe ein wenig das Gefühl, dass du den Schwierigkeitsgrad von C++ unterschätzt und denkst, dass du mit deinen Java-Kenntnissen ziemlich weit in C++ kommst. Dem ist aber definitiv nicht so!

    Ich glaube ich empfehle lieber ein Buch. Da du dich schon ein wenig im Programmieren auskennst, wäre wohl diese Lektüre für dich geeignet:
    Die C++-Programmiersprache | ISBN: 382731660X

    Grüssli



  • Fenixx schrieb:

    Es verwirrt mich nur deswegen, weil in meinen Augen Header-Dateien in gewisser Weise auch eine Klassendefinition, wie die eines Interfaces darstellen.
    Für IVogel habe ich demnach keine Header-Datei, sondern nur eine Cpp-Datei. Ist das so richtig?

    Du widersprichst dir selbst hehe.
    IVogel packt man natürlich in einen header. Denn man sollte keine .cpp includen, da das oft zu mehrfach definierten Symbolen führt und User der API verwirren würde.
    Also:
    Interfaces in eine .h/.hpp
    Implementation in eine .cpp
    rya.


Log in to reply