Definition: Polymorphie



  • Irgendwie habe ich Schwierigkeiten mit dem Begriff "Kompilationszeit-Polymorphie". Bezieht sich das auf Templates?

    Kannst du ein Beispiel dafuer bringen?



  • ja, templates:

    template <class Fahrzeug>
    void gib_gas (Fahrzeug& f, int speed)
    {
       f.beschleunige(speed); //wundersame compile-time polymorphie
    }
    
    int main ()
    {
       Auto a;
       Bike b;
       gib_gas (a);
       gib_gas (b);
    }
    


  • DEvent schrieb:

    Irgendwie habe ich Schwierigkeiten mit dem Begriff "Kompilationszeit-Polymorphie". Bezieht sich das auf Templates?

    Kannst du ein Beispiel dafuer bringen?

    class Shape {
    public: virtual void draw();
    };
    
    class Rectangle : public Shape {
    public: void draw();
    };
    
    class Circle : public Shape {
    public: void draw();
    };
    
    void foo(Shape& p) {
      p.draw();
    }
    
    //---
    
    class Rectangle {
    public: void draw();
    };
    
    class Circle {
    public: void draw();
    };
    
    template<class Shape>
    void foo(Shape& p) {
      p.draw();
    }
    


  • Sind Templates nicht so eine art intelligenter Textersetzer?

    template<class Shape>
    void foo(Shape& p) {
      p.draw();
    }
    
    foo(Rectangle()); // hier wird doch einfach <Shape> durch Rectangle ersetzt
    // so das der Compiler das kompiliert:
    
    void foo(Rectangle& p) { p.draw(); }
    foo(Rectangle());
    

    Also bei Templates erstellt der Compiler dir die void foo(Rectangle& p); Funktion, basierend auf das Template template<class Shape> void foo(Shape& p);.

    Dabei werden auch Typueberpruefung und so weiter automatisch vom Compiler erdegt.

    Ich wuerde das nicht als echte Polymophie bezeichnen, den das ist eigentlich nur Einsparung von Tipparbeit. Ist halt Kompilationszeit-Polymorphie.

    Das waere doch das gleich:

    #define foo(ta, tb, a, b) int foo(ta a, tb b) { return a * b; }
    
    int a = foo(Bar, Baz, new Bar(), new Baz);
    

    Ist das auch Kompilationszeit-Polymorphie?



  • DEvent schrieb:

    Sind Templates nicht so eine art intelligenter Textersetzer?

    der präprozessor ist ein textersetzer, templates können schon ein bisschen mehr.

    ändert sich vielleicht etwas an deiner auffassung, wenn du dir das beispiel mit C++0x-concepts denkst?

    Ich wuerde das nicht als echte Polymophie bezeichnen, den das ist eigentlich nur Einsparung von Tipparbeit.

    ja, weil du als "echte polymorphie" nur das kennst, was lehrbücher zu polymorphie mit C++ und virtual schreiben. ändert aber nichts daran, dass das genauso polymorphie ist. der unterschied ist nur folgender:
    bei shades beispiel wird abhängig vom statischen typen die richtige funktion aufgerufen, bei deiner "echten polymorphie" eben abhängig vom dynamischen typen. welcher typ ist der "echte" typ? kommt eben einfach darauf an, von welcher perspektive es du betrachtest: vom kompilierer oder aus der laufenden anwendung heraus - daher der begriff kompilierzeit-polymorphie.

    /edit: hier ein *richtiges* beispiel zur kompilierzeit-polymorphie ohne templates.

    class Shape
    {
    public:
       virtual void draw () = 0;
       //kein virtueller Destruktor!
    };
    
    class Rectangle : public Shape
    {
    public:
       void draw () { cout << "drawing Rectangle\n"; }
       ~Rectangle () { cout << "~Rectangle\n"; }
    };
    
    int main ()
    {
       Shape const& r = Rectangle();
    
       r.draw(); //Laufzeit-Polymorphie (außer dein Compiler ist intelligent genug)
    
       //kein virtueller Konstruktor nötig -> Kompilierzeit-Polymorphie   
    }
    


  • DEvent schrieb:

    Sind Templates nicht so eine art intelligenter Textersetzer?...

    Ähhh selbst wenn das so wäre: Was hätte das zu bedeuten ?
    Das eine ist ein Programmierparadigma ("Polymorphie"), das andere eine Technik.
    Genauso könnte man sagen "virtual ist doch nur eine Art zusätzliche Indirektion" ... spricht doch auch nicht dagegen, dass es eine Technik zur Umsetzung von Polymorphie ist.
    (selbst Polymorphie ist ja auch nur ein Werkzeug, mit dem man in einer bestimmten Situation ein bestimmtes Ziel erreichen kann (und andere eben nicht))

    DEvent schrieb:

    ...
    Ich wuerde das nicht als echte Polymophie bezeichnen, den das ist eigentlich nur Einsparung von Tipparbeit....

    Auch "virtual- oder Java-Polymorphie" kannst Du als "nur Einsparung von Tipparbeit" bezeichnen (man spart sich die Fallunterscheidungen und den Aufruf der jeweils passenden Funktion).

    DEvent schrieb:

    ...

    #define foo(ta, tb, a, b) int foo(ta a, tb b) { return a * b; }
    
    int a = foo(Bar, Baz, new Bar(), new Baz);
    

    Ist das auch Kompilationszeit-Polymorphie?

    Klar !
    Es wurde nur eine recht unsichere Technik dafür verwendet...

    @Topic: "polymorph" = "vielgestaltig"
    Alles, was darüber hinausgeht, ist je nach Anwendungsbereich Philosophie-(wenn nicht gar Ideologie-)-Sache.
    Kann man prima drüber streiten, ohne zu einem Ende zu kommen.

    Gruß,

    Simon2.



  • Lustig wird es, wenn wir weiter denken - die Argumentation ist ja die, dass Templates statisch sind und daher keine Polymorphie sein koennen (wer auch immer polymorphie durch Laufzeit definiert).

    Es spricht aber absolut nichts dagegen Templates zur Laufzeit auszuwerten. Naja, es spricht dagegen dass es idR unpraktisch ist, aber technisch ist es kein Problem. Denn wir sind in einer Zeit wo wir waehrend der Laufzeit kompilieren und das dauernd machen. Wir koennen problemlos Templates zur Laufzeit auswerten und C++ Interpreter muessen dies ja sogar machen.

    Aber diese Diskussion ist langweilig - denn jetzt kommen die Leute die sagen dass Templates nunmal etwas statisches sind und daher keine Polymorphie sein koennen. Dann beweisen wir, dass Templates sehr wohl dynamisch sein koennen und die Gegner weigern sich das zu aktzeptieren da man Templates mit Textersetzung implementieren kann. Dann wird die Diskussion metaphysisch und betrifft Implementation versus Konzepte und es geht komplett am Thema vorbei.

    Polymorphie ist naemlich "Sender schickt Botschaft an Empfaenger und Empfaenger reagieren unterschiedlich darauf". Genau das ist Polymorphie. In dieser Definition kommt nichts von Laufzeit/Compiletime vor (wobei wir diesen Unterschied heute sowieso nicht mehr haben).

    Wenn man aber das einmal verstanden hat (und das versteht man nicht so einfach wenn man nur Objekt Orientiert denkt) dann kann man mit Polymorphie richtig nette Sachen machen. Das Problem aber ist, dass C++ aussieht wie eine Objekt Orientierte Sprache, aber in wirklichkeit eine Multi Paradigmen Sprachen ist. Man kann funktionale Programmieren, generisch, etc. und eben auch Objekt Orientiert. Deshalb lassen sich Objektorientierte Konzepte nicht immer 1:1 uebertragen - da C++ eben mehr ist. Von Sprachen die Grundlegend anders aufgebaut sind mal komplett abgesehen - multidispatching und konsorten erlaubt eine komplett andere Dimension von Polymorphie.



  • Shade Of Mine schrieb:

    Aber diese Diskussion ist langweilig

    sie kommt mir so bekannt vor?



  • queer_boy schrieb:

    Shade Of Mine schrieb:

    Aber diese Diskussion ist langweilig

    sie kommt mir so bekannt vor?

    mindestens 3 mal schon in diesem forum und 120 mal woanders gefuehrt.

    das problem ist, dass manche leute immer die implementierung sehen wenn sie ein konzept sehen und nicht das konzept ansich. das bringt c++ halt leider mitsich 😕



  • queer_boy schrieb:

    Shade Of Mine schrieb:

    Aber diese Diskussion ist langweilig

    sie kommt mir so bekannt vor?

    Mich erinnert sie an die Diskussion um die Definition von Objekt-Orientierung. Dort wurde sich daran aufgehangen, dass statische und dynamische Polymorphie beides Polymorphie sei und dynamische Polymorphie deshalb nicht zur Definition von Objekt-Orientierung alleine herangezogen werden dürfe. Was so natürlich Unsinn ist. Aber bevor wir wieder 30 Seiten diskutieren 😃



  • Abteilung Xin?



  • Statische Polymorphie ist zur Kompilezeit dynamisch, klar. 🙄 Und irgendwie ist ja doch alles dynamisch, fragt sich nur wann.
    A)

    std::vector<X> foo(10);
    std::vector<Y> foo(10);
    

    😎

    X foo[10];
    Y foo[10];
    

    Was ist jetzt kompilezeit Polymorphie und was nicht und warum?



  • Shade Of Mine schrieb:

    Lustig wird es, wenn wir weiter denken - die Argumentation ist ja die, dass Templates statisch sind und daher keine Polymorphie sein koennen (wer auch immer polymorphie durch Laufzeit definiert).

    Es spricht aber absolut nichts dagegen Templates zur Laufzeit auszuwerten.

    Das ist jetzt aber nur ein Argument gegen die Bezeichnungen Laufzeit- bzw. Compilezeit-Polymorphie. An der grundsätzlichen Sachlage ändert sich dadurch erstmal nichts.



  • Shade Of Mine schrieb:

    queer_boy schrieb:

    Shade Of Mine schrieb:

    Aber diese Diskussion ist langweilig

    sie kommt mir so bekannt vor?

    mindestens 3 mal schon in diesem forum und 120 mal woanders gefuehrt.

    das problem ist, dass manche leute immer die implementierung sehen wenn sie ein konzept sehen und nicht das konzept ansich. das bringt c++ halt leider mitsich 😕

    Ist ja schon gut, ihr habt mich ueberzeugt. Ich habe auch nirgens gesagt das Tamplates oder mein Define-Beispiel keine Polymophie ist. Ist halt fuer mich keine "richtige", weil man den Typ des Objektes aendern will, das Programm anhalten, neu kompilieren und wieder von neuem starten muss.

    Wenn das anhalten, kompilieren, starten entfaellt (egal wie), dann ist es fuer mich "richtige" Polymophie.

    Ausserdem war meine Aussage in diesem Thread das man fuer Polymophie keine Vererbung braucht.



  • DEvent schrieb:

    Ist ja schon gut, ihr habt mich ueberzeugt. Ich habe auch nirgens gesagt das Tamplates oder mein Define-Beispiel keine Polymophie ist. Ist halt fuer mich keine "richtige", weil man den Typ des Objektes aendern will, das Programm anhalten, neu kompilieren und wieder von neuem starten muss.

    Diese negative Stimmung war nicht gegen dich gerichtet.

    Wenn das anhalten, kompilieren, starten entfaellt (egal wie), dann ist es fuer mich "richtige" Polymophie.

    Mir persönlich ist das zu eng definiert. Denn wann ich kompiliere ist nur eine Implementierungsfrage - die .NET Generics zB kompilieren die Templates on demand. In Java wird zB garnichts kompiliert bei den Generics, da werden "nur" Textersetzungen gemacht. Deshalb finde ich es immer komisch wenn man anhand des kompilierens etwas definieren will.

    Templates bieten aber nur statische Polymorphie, die natürlich nicht so dynamisch ist wie dynamische Polymorphie, aber dafür Sachen erlaubt die dynamische Polymorphie nicht bietet. zB kann ich Adapter ohne laufzeit kosten implementieren, ich habe kleinere Objekte, ich kann polymorphie aufrufe inlinen. Und das wichtigste: ich kann generisch programmieren.

    @Bashar: und die grunsätzliche Sachlage wäre?



  • DEvent schrieb:

    ...Ist halt fuer mich keine "richtige", weil man den Typ des Objektes aendern will, das Programm anhalten, neu kompilieren und wieder von neuem starten muss....

    Das ist bei Laufzeitpolymorphie (jedenfalls in C++) übrigens auch nicht anders, da man ohne Recompile sowieso nicht den Typ eines Objekts ändern kann. Mann kann lediglich seinen Blickwinkel auf dieses Objekt ändern, indem man es nur aus der Sicht seiner Basisklasse betrachtet.

    (kein Beispiel für gutes Design, sondern lediglich zur Veranschaulichung)

    struct A {   virtual void af(); };
    struct B {   virtual void bf(); };
    struct C : A, B {}
    
    int main() {
       C c; //es IST ein Objekt vom Typ C
       A* a = &c;
       B* b = &c;
    
       a->af(); // hier betrachte ich es aus dem A-Blickwinkel ... es bleibt aber ein C
    
       b->bf(); // hier betrachte ich es aus dem B-Blickwinkel ... es bleibt aber ein C
    }
    

    MUSS auch so sein, sonst wäre virtual irgendwie unsinnig (es sollen ja gerade C::af() und C::bf() aufgerufen werden).

    Gruß,

    Simon2.



  • Mir persönlich ist das zu eng definiert. Denn wann ich kompiliere ist nur eine Implementierungsfrage - die .NET Generics zB kompilieren die Templates on demand. In Java wird zB garnichts kompiliert bei den Generics, da werden "nur" Textersetzungen gemacht. Deshalb finde ich es immer komisch wenn man anhand des kompilierens etwas definieren will.

    Ich habe aber auch anhalten, kompilieren, und neu starten gesagt. Wenn man z.B. COM, Serialisierung oder Reflection benutzt, dann muss man das Programm weder anhalten noch neu uebersetzen, um das Objekt zu benuzten.

    Das finde ich eines der wichtigsten Vorteile von Polymorphie, man kann das Objekt zur Laufzeit des Programmes austauschen.



  • Templates interpretieren ist und bleibt Templates interpretieren, egal wann es gemacht wird und was erzeugt wird.

    Wenn du verschiedene Klassen hast die alle eine "draw" Methode haben und z.B. nen Kreis, ne Linie und ein Rechteck zeichenen, dann kann die Basisklasse polymorphes Verhalten aufweisen, je nachdem wie es überschrieben wurde.

    Wenn du jetzt nur eine Klasse hast und die ein Template nimmt auf den "Kreis", "Linie" oder "Rechteck" steht und die dann das entsprechende zeichnet, dann ist das keine Polymorphie, sondern es sind einfach nur unterschiedliche Eingabeparameter. Und wenn dazu Code erzeugt wird der das entsprechende zeichnet, ist es auch nur Template interpretieren.



  • DEvent schrieb:

    Mir persönlich ist das zu eng definiert. Denn wann ich kompiliere ist nur eine Implementierungsfrage - die .NET Generics zB kompilieren die Templates on demand. In Java wird zB garnichts kompiliert bei den Generics, da werden "nur" Textersetzungen gemacht. Deshalb finde ich es immer komisch wenn man anhand des kompilierens etwas definieren will.

    Ich habe aber auch anhalten, kompilieren, und neu starten gesagt. Wenn man z.B. COM, Serialisierung oder Reflection benutzt, dann muss man das Programm weder anhalten noch neu uebersetzen, um das Objekt zu benuzten.

    Das finde ich eines der wichtigsten Vorteile von Polymorphie, man kann das Objekt zur Laufzeit des Programmes austauschen.

    Wie sieht es mit .NET aus? Dort werden Generics zur Laufzeit kompiliert. Ich kann einen Typen herumreichen und dann daraus zB eine Collection erstellen die dann eben erst kompiliert wird. Der Typ muss dabei nicht von mir vorgegeben werden sondern kann von irgendeinem Plugin kommen.

    Auf Plattformen wie Java und .NET gibt es keine Trennung von kompilierung und laufzeit. Und ein C++ interpreter wuerde sowieso nie kompilieren...

    Aber das was du meinst ist eben _dynamische_ Polymorphie. Sie hat durchaus ihre Vorteile gegenueber statischer Polymorphie. Aber die Idee dahinter ist die selbe. Ich schicke eine Botschaft an einen Empfaenger und dieser reagiert unterschiedlich. Worueber wir hier reden ist die Definition wie man Botschaften sendet, nicht was Polymorphie ist. Wer aus der Java Ecke kommt wird statische Polymorphie nie aktzeptieren koennen, wer aus einer JavaScript Ecke kommt wird Interfaces nie aktzeptieren koennen. Es sei denn die Leute fangen an ueber ihren Horizont zu schauen 😉

    Viele Design Pattern die polymorphie verlangen sind mit statischer Polymorphie problemlos loesbar: darunter wohl am bekanntesten: Strategy, Iterator,...



  • Shade Of Mine schrieb:

    Ich schicke eine Botschaft an einen Empfaenger und dieser reagiert unterschiedlich.

    Ja, das Problem ist nur, dass Templates schon mal garnicht reagieren können. Und wenn du eine Botschaft z.B. "int" an irgend einen konkreten Interpreter sendest, der das Template interpretiert, dann wird der immer gleich reagieren. Wenn du eine zweite Botschaft an den gleichen Interpreter sendest, dann wird er auf diese auch immer gleich reagieren. Das Ergebnis kann anders sein, wenn die Botschaft eine andere war, dass ist aber nicht Polymorphie.


Anmelden zum Antworten