OOP: soll man jetzt alles in ne Klasse packen oder watt?



  • sqrt ist doch perfekt dokumentiert: du schaust in die doku und da steht
    int sqrt(int); //ermittelt die quadratwurzel einer zahl und returned diese

    und dann muss ich nicht nachsehen ob das fuer double anders ist. weil es fuer double definitionsgemaess genau gleich ist.

    Manche Funktionen sind Typenabhänig.
    Z.B. Die Division. int div(int x, int y) ist was anderes als double div(double x, double y). Auch die Funktion betrag() ist was anderes für normale Zahlen, Vektoren, komplexe Zahlen.
    Muss gestehen das ich mir bei diesem Argument nicht ganz sicher bin. Ist bestimmt ziemlich schwaches Argument.

    Mal das Beispiel div:
    int div(int x, int y).
    Man kann es verschieden Implementieren, man erhält verschiedene Ergebnisse.

    int div(int x, int y)
    {
        double y = (double)x / (double)y;
        return round_abwärst(y);
    }
    
    int div(int x, int y)
    {
        double y = (double)x / (double)y;
        return round_aufwärst(y);
    }
    
    int div(int x, int y)
    {
        double y = (double)x / (double)y;
        return schneide_nachkomme_ab(y);
    }
    
    int div(int x, int y)
    {
        return y = ganzzahlige_division(x, y);
    }
    

    naja usw usf.

    class Bitmap : public ISwapable {
    public:
      virtual void swap(Bitmap&);
    };
    

    Das Beispiel auf Namespaces bezogen würde doch eher so aussehen:

    namespace bitmap
    {
        void swap(Bitmap& b)
        {
            std:swap(b.intern_daten);
        }
    }
    

    Wieso sollte deine spezielle Funktion eigentlich überhaupt im Namespace std liegen? Gibt es dafür einen Grund (ausser den Leser des Codes zu verwirren) ?

    In der Bibliothek STL wird doch nirgendwo deine spezielle Funktion aufgerufen.

    dann kannst du genauso sagen es macht keinen sinn klassen zu verwenden, weil ja jeder eine funktion draw() einbauen koennte und dann hast du 10 draw() funktionen...

    Klar gibt es 10 draw()-Methoden, aber sie liegen in 10 verschiedenen Klassen. Du hast 10 draw()-Funktionen und sie liegen alle im namespace std.

    ne, ne, ne. soviel uebersicht muss das team schon haben dass sie jede schnittstelle einer klasse nur einmal implementieren.

    Eben nicht, die Sprache sollte dies "von Haus aus" absichern. Das war auch der Gedanke bei Namespace in C++, packages bei Java usw.

    Mir fällt auch grade ein, das du das Bitmap-Beispiel falsch hast.
    Das Interface Swapable kann nicht so sein, es müsste:

    public interface Swapable
    {
        void swap(Object a);
    }
    
    public class Bitmap implements Swapable
    {
       void swap(Object a)
       {
           Bitmap b = (Bitmap)a;
           b.spaw_data();
       }
    }
    

    Bei deiner "statischen Polymorphie" erweiterst du das Interface Swapable um eine Methode: void swap(Bitmap b);

    oder vielleicht steht da sogar nur
    template<typename T>
    T sqrt(T);

    Das wäre das optimale. Jetzt kann sqrt() mit allem umgehen, das den Operator double() anbietet. Was spricht den dagegen, das du so dagegen bist?



  • DEvent schrieb:

    Manche Funktionen sind Typenabhänig.
    Z.B. Die Division. int div(int x, int y) ist was anderes als double div(double x, double y). Auch die Funktion betrag() ist was anderes für normale Zahlen, Vektoren, komplexe Zahlen.

    nicht wirklich. ein div sollte fuer int und double wohl gleich aussehen...

    Das Beispiel auf Namespaces bezogen würde doch eher so aussehen:

    namespace bitmap
    {
        void swap(Bitmap& b)
        {
            std:swap(b.intern_daten);
        }
    }
    

    und wieso ist das besser als swap() in std zu packen?

    ich kann dann halt nicht mehr:

    template<typename T>
    void foo(T& a, T& b) {
      std::swap(a,b);
    }
    

    machen. ich darf das std nicht dazu schreiben und der koenig lookup kommt dann rein. naja... ist das wirklich schoener?

    Wieso sollte deine spezielle Funktion eigentlich überhaupt im Namespace std liegen? Gibt es dafür einen Grund (ausser den Leser des Codes zu verwirren) ?

    was verwirrt dich?

    In der Bibliothek STL wird doch nirgendwo deine spezielle Funktion aufgerufen.

    und?

    Klar gibt es 10 draw()-Methoden, aber sie liegen in 10 verschiedenen Klassen. Du hast 10 draw()-Funktionen und sie liegen alle im namespace std.

    wo ist das problem wenn sqrt fuer 10 verschiedene typen implementiert ist? was stoert daran?

    Eben nicht, die Sprache sollte dies "von Haus aus" absichern. Das war auch der Gedanke bei Namespace in C++, packages bei Java usw.

    du verstehst nicht.

    ich kann nur ein MyInt sqrt(MyInt) anlegen genau wie ich nur ein MyInt::sqrt() anlegen kann. der sprache sichert das ab.

    Mir fällt auch grade ein, das du das Bitmap-Beispiel falsch hast.
    Das Interface Swapable kann nicht so sein, es müsste:

    public interface Swapable
    {
        void swap(Object a);
    }
    
    public class Bitmap implements Swapable
    {
       void swap(Object a)
       {
           Bitmap b = (Bitmap)a;
           b.spaw_data();
       }
    }
    

    Bei deiner "statischen Polymorphie" erweiterst du das Interface Swapable um eine Methode: void swap(Bitmap b);

    schau es dir nochmal an und dann sag mir dass statische polymoprhie hier nicht besser ist.

    du verstehst etwas nicht:
    ich fuege keine funktion hinzu. es kommt keine funktionalitaet hinzu. auch wenn swap physikalisch in std liegt ist es teil des interfaces von Bitmap.



  • Shade Of Mine schrieb:

    auch wenn swap physikalisch in std liegt ist es teil des interfaces von Bitmap.

    Der Satz muss einem doch schon zu denken geben. "a gehört zu b, ist aber an ganz anderer Stelle zu finden". Mir sagt da mein Instinkt, dass das nicht gut sein kann. 😉

    BTW: Definiere mal "Interface".



  • Gregor schrieb:

    BTW: Definiere mal "Interface".

    Math bietet ein interface an. Es definiert funktionen die auf ein objekt angewendet werden koennen.

    ihr seht das alles viel zu konservativ. dass man std::swap spezialisiert ist im c++ standard so vorgesehen, dass ist keine kranke erfindung von mir oder volkard.

    es ist eben ein anderes denken. wie gesagt: in lisp definiert man _alle_ methoden auf exakt diese art.

    OOP hat nix mit klassen zu tun. klingt komisch, ist aber so.

    ich mach ein Math.sqrt(a); und egal was a ist, sofern es das Math.sqrt interface implementiert liefert es mir die quadratwurzel.

    es ist wirklich nur eine andere schreibweise fuer herkoemmliche interfaces. wir koennen uns streiten in welchen namespace das gehoert, aber es spricht nichts gegen den namespace std. denn es kann zu keiner kollision kommen und die funktion sqrt liegt in der selben datei definiert wie die klasse.

    ich weiss, es ist komisch. aber so funktioniert statische polymorphie.



  • Shade Of Mine schrieb:

    OOP hat nix mit klassen zu tun. klingt komisch, ist aber so.

    Wir reden hier ja wohl nicht über OOP, oder? Namespaces haben genausowenig mit OOP zu tun, wie Klassen, in denen lauter statische Methoden anzutreffen sind. In der OOP ist "Schnittstelle" ein genau definierter Begriff, der nicht auf ein swap in irgendeinem Namespace angewandt werden kann. Deshalb frage ich nach der Definition. Auf welchen Schnittstellenbegriff beziehst Du Dich?



  • Gregor schrieb:

    Auf welchen Schnittstellenbegriff beziehst Du Dich?

    vergiss die namespaces. sie verwirren dich und lenken vom thema ab.

    wie wuerdest du folgendes nennen?

    du hast 3 Typen: Integer, int, double.

    Alle 3 Typen bieten dir folgende operation an:
    sqrt()

    du kannst
    a.sqrt();
    machen unabhaengig ob a jetzt den Typ Integer, int oder double hat.

    Wuerdest du jetzt sagen dass Integer, int und double ein interface anbieten dass sqrt implementiert?

    Im prinzip schon, oder?

    nun stellen wir uns vor das ganze ist nun anders rum:
    Integer, int und double sind keine klassen die ein interface implementieren. sondern sie implementieren eine funktion.

    das selbe prinzip, nur anders rum 🙂

    exakt das haben wir hier: es sind objekte. es ist polymoprhie. Es ist aber auch statisch. und sqrt gehoert nun eben zu Math. Und ich implementiere das interface indem ich sqrt spezialisiere fuer meinen typen...



  • ich kann nur ein MyInt sqrt(MyInt) anlegen genau wie ich nur ein MyInt::sqrt() anlegen kann. der sprache sichert das ab.

    Nein die Sprache sichert es eben nicht ab.

    Wenn Entwickler A an einem Modul Bildschirm arbeitet und Entwickler B an Modul Drucker. Beide Entwickler brauchen die Funktion sqrt(double). Entwickler A implementiert nun sqrt(double) steckt es in namespace std. Entwickler B macht genau das selbt.
    Am Ende, wenn beide Module in einen Programm verwendet werden gibt es haufenweise Compilerfehler, weil es zig sqrt(double) im namespace std gibt.

    Wozu war das nun gut?

    Anstatt das Entwickler A sein sqrt() in namespace bildschirm und Entwickler B sein sqrt() in namespace drucker reinschreibt, damit es keine Mehrdeutigkeiten gibt.

    Deine Methode bietet einfach keineler Vorteile, mehr noch sie verursacht haufen Probleme.

    Das selbe ist halt mit Klassen.

    Zur besseren Verwaltung gleichartiger Objekte bedienen sich die meisten Programmiersprachen des Konzeptes der Klasse. Klassen sind Vorlagen, aus denen Objekte zur Laufzeit erzeugt werden (Instanzen). Im Programm werden dann nicht einzelne Objekte, sondern eine Klasse gleichartiger Objekte definiert.

    Man kann sich die Erzeugung von Objekten aus einer Klasse vorstellen wie das Fertigen von Autos aus dem Konstruktionsplan eines bestimmten Fahrzeugtyps. Klassen sind die Konstruktionspläne für Objekte.

    Also du willst neue Eigenschaften hinzufügen. Soetwas macht man aber durch Vererbung. Vererbung heißt aber das die Basis-Klasse inverändert bleibt. Sie wird spezialisiert durch Unterklassen.
    Du aber veränderst die Basisklasse ( namespace std ) und speziallisierst sie so. Das ist kein OOP.

    exakt das haben wir hier: es sind objekte. es ist polymoprhie. Es ist aber auch statisch. und sqrt gehoert nun eben zu Math. Und ich implementiere das interface indem ich sqrt spezialisiere fuer meinen typen...

    Deswegen gehört dein sqrt nicht mehr in Math. Dein sqrt gehört in deine Klasse / namespace what ever.



  • Gregor schrieb:

    Shade Of Mine schrieb:

    OOP hat nix mit klassen zu tun. klingt komisch, ist aber so.

    Wir reden hier ja wohl nicht über OOP, oder? Namespaces haben genausowenig mit OOP zu tun, wie Klassen, in denen lauter statische Methoden anzutreffen sind. In der OOP ist "Schnittstelle" ein genau definierter Begriff,

    der wesentlich breiter gefaßt ist, als das interface-schlüsselwort.

    der nicht auf ein swap in irgendeinem Namespace angewandt werden kann.

    doch.



  • DEvent schrieb:

    Du aber veränderst die Basisklasse ( namespace std ) und speziallisierst sie so. Das ist kein OOP.

    nö. er ändert doch keine klasse namens std. die gibt's doch gar nicht.



  • DEvent schrieb:

    Deswegen gehört dein sqrt nicht mehr in Math. Dein sqrt gehört in deine Klasse / namespace what ever.

    aber gern.

    class Bitmap{
    private:
       char* data;
    ...
    public:
       friend template<> std::swap<Bitmap&>(Bitmap& a,Bitmap& b){
          std::swap(a.data,b.data);
       }
    };
    

    gefällt die das jetzt besser?

    eine klasse ist swappable, wenn sie swap anbietet. dazu muß nix geerbt werden. man muß es auch nirgends anmelden. man baut einfach swap, und dann gehört sie zum klub.



  • Shade Of Mine schrieb:

    wie wuerdest du folgendes nennen?

    du hast 3 Typen: Integer, int, double.

    Alle 3 Typen bieten dir folgende operation an:
    sqrt()

    du kannst
    a.sqrt();
    machen unabhaengig ob a jetzt den Typ Integer, int oder double hat.

    Polymorphie würde ich das nennen.

    Shade Of Mine schrieb:

    Wuerdest du jetzt sagen dass Integer, int und double ein interface anbieten dass sqrt implementiert?

    Im prinzip schon, oder?

    OMG!!! 😉 Nieeeee. Ich weiß nicht, welchen Schnittstellenbegriff Du hast, bist ja immer noch nicht mit einer Definition herausgekommen, aber wenn in Deiner Definition etwas enthalten ist, das besagt, dass eine Schnittstelle etwas implementiert, dann fände ich das schon sehr sehr komisch. Eine "Schnittstelle" ist doch in jedem Fall etwas, was man unabhängig von einer Implementation definiert.

    Shade Of Mine schrieb:

    nun stellen wir uns vor das ganze ist nun anders rum:
    Integer, int und double sind keine klassen die ein interface implementieren. sondern sie implementieren eine funktion.

    das selbe prinzip, nur anders rum 🙂

    Hä? Verstehe ich nicht? Erstens: Was heißt "Implementierung einer Funktion"? Zweitens: Was ist da andersherum?

    Shade Of Mine schrieb:

    exakt das haben wir hier: es sind objekte. es ist polymoprhie. Es ist aber auch statisch. und sqrt gehoert nun eben zu Math. Und ich implementiere das interface indem ich sqrt spezialisiere fuer meinen typen...

    Ich sehe den Zusammenhang zum Rest Deines Beitrags nicht. ...und ich sehe auch immer noch nicht, wie das mit der Definition des Begriffs "Schnittstelle" zusammenhängt. Mir kommt es irgendwie folgendermaßen vor: Du sagst, eine Methode bzw. dessen Signatur kann zu der Schnittstelle einer Klasse gehören. Dann sagst Du, jetzt nehmen wir die Methode da mal raus und organisieren die in einem Namespace mit anderen Methoden gleichen Namens. Dann fragst Du mich, wie man das dann nennt und erwartest als Antwort "Schnittstelle". Das stimmt aber nicht. Das ist keine Schnittstelle. Wie Du selbst sagst, ist es eben etwas ganz anderes. Das ist eine Menge von globalen Funktionen. Eine Schnittstelle ist aus meiner Sicht eine formalisierte Beschreibung (zum Beispiel der Methoden, die die Objekte einer Klasse anbieten). Was Du da hast, ist keine formalisierte Beschreibung mehr, sondern eine Gruppierung ähnlicher Funktionalität für unterschiedliche Typen. ...halt etwas völlig anderes.



  • DEvent schrieb:

    Wenn Entwickler A an einem Modul Bildschirm arbeitet und Entwickler B an Modul Drucker. Beide Entwickler brauchen die Funktion sqrt(double). Entwickler A implementiert nun sqrt(double) steckt es in namespace std. Entwickler B macht genau das selbt.

    Am Ende, wenn beide Module in einen Programm verwendet werden gibt es haufenweise Compilerfehler, weil es zig sqrt(double) im namespace std gibt.

    Wozu war das nun gut?

    fuer garnichts. du hast nicht gelesen was ich geschrieben habe.

    als 1) mal: "meine" methode ist die, die man laut c++ standard macht.
    und 2)

    sqrt wird nicht von mir erfunden. sqrt ist teil der standard library. sqrt ist fuer eine million typen definiert. ich mach nichts anderes als die ein million und erste spezialisierung zu adden.

    das ist wovon ich rede:
    es gibt ein interface: sqrt.

    das habe nicht ich erfunden. ich fuege keine neue funktion hin zu.



  • STL Doc schrieb:

    template <class Assignable>
    void swap(Assignable& a, Assignable& b);

    Ehm ok generische Programmierung.
    Ehrlich gesagt ich bin total erschlagen, und weiss nicht mehr worüber diskutiert.
    Wahrscheinlich tretten sich auch nur paar Programmierparadigmen 😛



  • Gregor schrieb:

    Ich sehe den Zusammenhang zum Rest Deines Beitrags nicht. ...und ich sehe auch immer noch nicht, wie das mit der Definition des Begriffs "Schnittstelle" zusammenhängt.

    swap() ist eine schnittstelle, ok?

    genau wie ISwapable.
    Damit meine klasse nun swap() nutzen kann, muss ich die funktion spezialisieren. (ist uebrigens standard c++ - wie gesagt, dass ist nicht meine erfindung oder so, sondern der c++ standard sagt das so).

    es gibt nun irgendwo diese funktion std::swap() fuer int, double, string,...

    nun moechte ich, dass meine klasse Bitmap dieses interface ebenfalls implementiert (normalerweise schreibt man jetzt: impelements ISwapable) und dazu muss ich lediglich die funktion std::swap() spezialisieren.

    wie volkard es so schoen geschrieben hat.

    Das ist keine Schnittstelle. Wie Du selbst sagst, ist es eben etwas ganz anderes. Das ist eine Menge von globalen Funktionen. Eine Schnittstelle ist aus meiner Sicht eine formalisierte Beschreibung (zum Beispiel der Methoden, die die Objekte einer Klasse anbieten).

    jetzt lehnen wir uns zurueck. und betrachten das ganze von neuem:

    Meine nicht-schnittstelle ist eine sammlung von globalen abstrakten funktionen (mangels besserem namen: einfach dem vertrag das void swap(T&,T&) die beiden params austauscht. es gibt keine konkrete implementierung (wie auch ISwapable keine konkrete implementierung hat) ist also quasi eine abstrakte funktion).

    Ein herkoemmliches java interface ist aber was? eine sammlung von abstrakten public funktionen.

    nenn es formalisierte beschreibung von aktionen die ein objekt taetigen kann - aber genau das sind meine abstrakten funktionen auch. sie definieren bestimmte aktionen die ein objekt taetigen kann. zB swap() definiert, dass das objekt "swapable" ist.

    Was Du da hast, ist keine formalisierte Beschreibung mehr, sondern eine Gruppierung ähnlicher Funktionalität für unterschiedliche Typen. ...halt etwas völlig anderes.

    Ich sehe da keinen unterschied:

    um ISwapable zu verwenden muss meine Klasse ISwapable implementieren.
    um swap nutzen zu koennen muss ich std::swap spezialisieren.

    es ist exakt das selbe.

    vergiss klassen. klassen haben mit oop nix zu tun.



  • Hmm

    Ich seh das so.

    Du spezialist die std:swap, in dem du diese Funktion aufrufst und für dich benutzt, richtig?

    -> Konkret ist das doch einfach nur ein Funktionsaufruf einer generische Funktion.

    Ich hab mal Bjarne Stroustrup "Die C++ Programmiersprache" durchsucht, und als Schnittstellen werden alle benutztbare (also öffentliche) Funktionen bezeichnet, so herausgelesen. Es gibst richtige eigene Definition Oo.

    Im gegensatz zu Java werden Schnittstellen als formale Beschreibung beschriben, diese werden mit eine Ableitung konkrete implementiert.



  • Zeus schrieb:

    Im gegensatz zu Java werden Schnittstellen als formale Beschreibung beschriben, diese werden mit eine Ableitung konkrete implementiert.

    Ok. Wo ist das "formale" daran? Formal heißt für mich in jedem Fall, dass ich ein Sprachmittel zur Verfügung habe, mit dem ich sagen kann: "Das da ist eine Schnittstelle!". Wie ist das in C++ gegeben? Wo ist denn die formale Schnittstellendefinition von swap?



  • lol sry vertipper in text

    sollte heissen:
    "In Java hingegen"

    Java hat die Sprachmittel
    - Interface-Keyword und
    - Implements-Keyword



  • Zeus schrieb:

    lol sry vertipper in text

    sollte heissen:
    "In Java hingegen"

    Java hat die Sprachmittel
    - Interface-Keyword und
    - Implements-Keyword

    Ah, ok. Kannst Du nochmal die Stelle im Stroustrup angeben, wo erklärt wird, was ne Schnittstelle bei C++ ist?



  • Ist das nicht viel zu theoretisch und schon eher philosophisch?

    Mir ist es eigentlich egal ob es jetzt laut irgendeiner definition als Interface durchgeht oder ich es Pseude-Interface nennen muss.

    Worum es geht ist, dass man auf diese Art und Weise genauso abstrakte Aktionen fuer ein Objekt definieren kann wie mit herkoemmlichen Interfaces.

    In C++ hat man sowieso viele "Memberfunktionen" ausserhalb der Klasse. Aber zB ein getline() gehoert fuer mich zur Schnittstelle von string.

    Schaut euch mal lisp an. Da hat man Objekte komplett ohne Klassen. Da hat man im Prinzip nur eine sammlung von globalen funktionen. Und dennoch hat man OO. In C kann ich auch OO arbeiten - natuerlich fehlen hier viele buildin features von besser ausgepraegten OO sprachen wie zB virtuelle methoden, aber auch dennoch kann ich OO programmieren. Und dann ist das Interface einer Klasse eine sammlung an globalen Funktionen.

    Ist natuerlich etwas komplett anderes als das herkoemmliche 08/15 OOP, aber nur weil ich sqrt(a) statt a.sqrt() schreibe ist es doch noch lange nicht etwas komplett anderes...



  • Gregor schrieb:

    Ah, ok. Kannst Du nochmal die Stelle im Stroustrup angeben, wo erklärt wird, was ne Schnittstelle bei C++ ist?

    S.180 .... wie gesagt, ne richtige Definition ist das leider nicht, aber man kann es ersehen.


Anmelden zum Antworten