Interface und Sichtbarkeit



  • inaj76 schrieb:

    Wie sollte (gutes Design) in der realisierenden Klasse die Sichtbarkeit für die Interface-Methode sein?

    Man kann in C++ die Sichtbarkeit nicht beinflußen, grundsätzlich ist alles in der Klasse sichtbar. Wenn man die Sichtbarkeit beeinflussen will dann muß man das Pimpl-Idiom (gibt noch eine Reihe von Namen dafür) nutzen.



  • ~john schrieb:

    inaj76 schrieb:

    Wie sollte (gutes Design) in der realisierenden Klasse die Sichtbarkeit für die Interface-Methode sein?

    Man kann in C++ die Sichtbarkeit nicht beinflußen

    Wovon redest Du? Da man offensichtlich über das 'private'-Schlüsselwort die Sichtbarkeit von Mitgliedern oder Basisklassen beeinflussen kann, musst Du etwas anderes meinen.

    Das Pimpl-Idiom hat damit nichts zu tun. Es reduziert Abhängigkeiten.



  • Hallo,

    danke, dass ihr euch die Zeit nehmt ...

    Ich versuche nochmal mein Problem zu erklären:

    Ich möchte gegen eine Schnittstelle implementieren und nicht gegen eine konkrete Implementierung. Aus diesem Grund verwende ich eine InterfaceKlasse.

    class CMyInterface
    {
    public:
    virtual void InterfaceMethode()=0;
    }
    

    Diese ist rein abstrakt und deren Methoden alle PUBLIC.

    Meine konkrete Klasse soll auch dieses Interface realisieren und implementiert die InterfaceMethode:

    class MyClass : public CMyInterface
    {
    public:
      [i]Klassenschnittstelle (sonstiger Code)[/i]
    protected:
      void InterfaceMethode() { [i]doing [/i]};
    private:
      [i]sonstiger Code[/i]
    }
    

    Jetzt zu meinem Verständnisproblem:
    Macht es Sinn, eine InterfaceMethode in der konkreten Implementierung (MyClass) überhaupt als public zu deklarieren? Dadurch das man ein Interface designed hat, drückt man doch aus, dass jemand, der die Methode aufrufen möchte, dies über den InterfaceTyp machen soll (-> implementiere gegen eine Schnittstelle). Wenn ich ebenfalls die InterfaceMethode in der konkreten Klasse (MyClass) PUBLIC deklariere, dann habe ich doch automatisch die InterfaceMethode auch zur Klassenschnittstelle von MyClass hinzugefügt. Das bedeutet, dass obwohl ich ein Interface anbiete, jeder über die konkrete Klasse die Methode aufrufen kann. Ist dies noch sinnvoll? oder ist dies der Sinn eines Interfaces? 😕

    Ich hoffe ich konnte mein Problem ein bisschen genauer erklären.
    Schon mal danke ... 🙂

    Gruß
    inaj76 😃



  • inaj76 schrieb:

    Macht es Sinn, eine InterfaceMethode in der konkreten Implementierung (MyClass) überhaupt als public zu deklarieren?

    Klar. Ich halte sogar alles andere für unsinnig.

    Dadurch das man ein Interface designed hat, drückt man doch aus, dass jemand, der die Methode aufrufen möchte, dies über den InterfaceTyp machen soll

    Nein, nicht „soll“ sondern kann. Du hast das mit dem „programmieren gegen eine Schnittstelle“ falsch verstanden: Das gilt zwar, aber doch nicht die ganze Zeit. Man implementiert am laufenden Band gegen konkrete Datentypen, nämlich jedes Mal, wenn man einen instanziert. Es gibt für die meisten Methoden überhaupt keinen Sinn, nicht gegen die konkrete Klasse zu programmieren. Lediglich für komplexere, entkoppelte (oder sehr allgemein gehaltene) Systeme sollte man sich vor konkreten Datentypen vorsehen.

    Wenn ich ebenfalls die InterfaceMethode in der konkreten Klasse (MyClass) PUBLIC deklariere, dann habe ich doch automatisch die InterfaceMethode auch zur Klassenschnittstelle von MyClass hinzugefügt. Das bedeutet, dass obwohl ich ein Interface anbiete, jeder über die konkrete Klasse die Methode aufrufen kann.

    Was spricht dagegen?



  • Diese ist rein abstrakt und deren Methoden alle PUBLIC.

    Warum nimmst du dann nicht struct?



  • Sinn eines Interfaces ist doch, dass alle abgeleiteten Klassen automatisch den Satz von Methoden, den das Interface deklariert, zur Verfuegung stellen. Dass bedeutet aber nicht, dass man die abgeleiteten Klassen unbedingt polymorph ueber einen Zeiger bzw. eine Referenz auf das Interface behandeln muss, sondern man kann sie auch direkt verwenden (Muss man auch, wenn sie zusaetzliche Methoden haben)



  • Die Betrachtung des Problems der Zugreifbarkeit kann man sich sparen, wenn man sich mal das NVI-Idiom anschaut:

    In der Basisklasse gibt es öffentliche nichtvirtuelle Funktionen, die das Interface darstellen. Diese Funktionen kann man immer erreichen, auch wenn man ein Objekt der abgeleiteten Klasse hat, und muss den Zugriffsmodifizierer nur einmal setzen. Diese Funktionen rufen private abstrakte Funktionen auf. Diese können dann auch in der abgeleiteten Klasse privat sein, sie werden nur "von innen" aufgerufen.

    Zudem hat das ganze den Vorteil dass man vor oder nach dem virtuellen Aufruf noch Code einfügen kann, ohne den Clientcode zu verändern.

    class Basis
    {
    public:
        void Paint() { DoPaint(); }
    
    private:
        virtual void DoPaint() = 0;
    };
    


  • (D)Evil schrieb:

    Diese ist rein abstrakt und deren Methoden alle PUBLIC.

    Warum nimmst du dann nicht struct?

    Ich denke, dass würde auch gehen, habe nicht daran gedacht. Interessant ...



  • Konrad Rudolph schrieb:

    Wenn ich ebenfalls die InterfaceMethode in der konkreten Klasse (MyClass) PUBLIC deklariere, dann habe ich doch automatisch die InterfaceMethode auch zur Klassenschnittstelle von MyClass hinzugefügt. Das bedeutet, dass obwohl ich ein Interface anbiete, jeder über die konkrete Klasse die Methode aufrufen kann.

    Was spricht dagegen?

    Ich habe mir gedacht, dass ich dann besser zwischen der Klassenschnittstelle und der InterfaceImplementierung unterscheiden könnte. Und ich würde alle Anwender die ein InterfaceFeature verwenden wollen zwingen, dies auch über einen InterfaceTyp zu tun (-> Unabhängigkeit von der konkreten Klasse). Deshalb biete ich ja ein Interface an, welches gewisse Features anbietet.

    Ich gebe dir aber Recht, dass es schon komisch ist, ein Interface zu realisieren und die InterfaceSchnittstelle nicht mit in die Klassenschnittstelle aufzunehmen 😕



  • pumuckl schrieb:

    Sinn eines Interfaces ist doch, dass alle abgeleiteten Klassen automatisch den Satz von Methoden, den das Interface deklariert, zur Verfuegung stellen.

    Die konkrete Klasse stellt die Funktionalität (Implementierung) auch zur Verfügung ...

    pumuckl schrieb:

    Dass bedeutet aber nicht, dass man die abgeleiteten Klassen unbedingt polymorph ueber einen Zeiger bzw. eine Referenz auf das Interface behandeln muss, sondern man kann sie auch direkt verwenden

    da könntest du Recht haben ...
    Ich frage mich halt, wieso soll jemand die Methoden direkt verwendet? Da könnte ich mir das Interface auch sparen, was eigentlich nicht der Sinn war.

    pumuckl schrieb:

    (Muss man auch, wenn sie zusaetzliche Methoden haben)

    Wenn diese zusätzliche Methoden haben, dann ist das Interface nicht vollständig



  • Dann reden wir hier grade alle aneinander vorbei. Unter einem INterface versteht man im allgemeinen eine abstrakte Basisklasse, die eine gemeinsame Schnittstelle für ihre abgeleiteten Klassen bietet. Diese abgeleiteten konkreten Klassen definieren alle in der Schnittstelle aufgelisteten Methoden, koennen aber durchaus auch weitere eigene Methoden besitzen und müssen nicht zwangsläufig polymorph über die Basisklasse angesprochen werden. Beispiel:

    Klasse Auto: jedes Auto kann (irgendwie) fahren, hupen, blinken, tanken.
    Klasse Kipplaster: ein Kipplaster ist ein Auto, ist deshalb öffentlich von Auto abgeleitet. Er fährt, blinkt, hupt und tankt auf seine eigene Art und Weise (und definiert deshalb die entsprechenden Methoden anders als beispeilsweise ein Kleinwagen). Aber ein Kipplaster kann auch Dinge, die nicht jedes Auto kann: Ladefläche kippen. Deshalb implementiert der Kipplaster das Ladeflächenkippen, was nicht zur allgemeinen Schnittstelle von Auto gehört.

    So wie ich dich jetzt verstanden habe, möchtest du die Schnittstelle von der Implementation trennen. Dazu verwendet man häufig das sogenannte pimpl-Idiom oder auch das Brücken-Pattern. Dazu gibts dann eine Schnittstellenklasse, die die eigentliche Arbeit an eine Implementationsklasse delegiert. Sinnvoll ist sowas hauptsächlich, wenn man in größeren Projekten die Kompilierungsabhängigkeiten reduzieren will oder wenn man verschiedene alternative Implementationsklassen zur Verfügung stellen will. Im letzten Fall leitet man alle Implementationsklassen von einer Basisklasse ab, die die allgemeine Schnittstelle der Implementationsklassen liefert. (Was aber nicht heißt, dass die Implementationsklassen keine weiteren Methoden für ihre eigenen zwecke definieren dürfen. Die Schnittstellenklasse und die Implementationsklasse haben oft nicht die gleiche Schnittstelle. Bsp:

    class CPU; //forward-deklaration für die implementationsbasisklasse
    
    class Computer {
    public: 
      Computer(CPU* cpu) : cpu_(cpu) {};
      void berechne(Aufgabe const& a);
    private:
      CPU* cpu_;
    };
    
    struct CPU {
      int analysiere(Aufgabe const& a) = 0;
    };
    
    void Computer::berechne(Aufgabe const& a) {
      int returnwert = cpu_->analysiere(a);
    }
    
    class Intel : public CPU {
      /*...*/
    };
    class AMD : public CPU {
      /*...*/
    };
    class C64 : public CPU {
      /*...*/
      void brenneDurch() {}; //kann nur der C64 ;)
    };
    
    int main () {
      Intel intel;
      AMD amd;
      C64 c64;
      Computer c(&intel);
      Aufgabe a;
    
      c.berechne(a); //berechnet mit dem intel...
    }
    

Anmelden zum Antworten