Statische und Dynamische Polymorphie: Weiter geht's



  • Hallo!
    Ich würde gerne mal weiter ein paar Meinungen/Ansichten/Vor-/Nachteile und Anwendungsbereiche zu diesem Thema hören, leider hat dieses Thema einfach in der Mitte aufgehört. 🙂
    Ich stelle einfach mal 2 Ansichten/Thesen in den Raum:

    Legende:
    SP: Statische Polymorphie
    DP: ----''--- Polymorphie

    1. DP verändert das OOP-Prinzip von C++

    Meines Erachtens schwächen Templates die strenge OO-Kapselung. Ein schönes Beispiel steht ja in ECP ("Effektiv C++ Programmieren"):

    [cpp]
    template <typename T>
    class Rational;

    template <typename T>
    Rational<T> doMultiply(const Rational<T> &l, const Rational<T> &r);

    template <typename T>
    class Rational {
    public:
    ...
    // friend, um gemischte Operatoren zu benutzen
    // wäre operator*() nicht in Rational definiert, würde beim Aufruf von
    // Rational<int> o = otherRational * 3
    // ein Compiler-Fehler kommen: 3 soll ein Rational<int> werden, de facto
    // kennt der Compiler int nicht, sondern nur T. Beim Einsatz einer Klasse ist
    // ihm bei der Deklaration des Operators sehr wohl T, also int, bekannt,
    // da T als int ja bei der Instanziierung der Klasse übergeben wird
    // implizit inline, da in Klasse definiert, ruft Helper wegen Blähcode auf
    friend const Rational operator *(const Rational &l, const Rational &r) {
    return doMultiply(l, r);
    }
    ...
    };

    // Helper, genaue Implementierung redundant
    Rational<T> doMultiply(const Rational<T> &l, const Rational<T> &r) {
    return Rational<T>(l.numerator() * r.numerator(), l.denominator() * r.demoniator());
    }
    [/cpp]

    Friend bröckelt etwas an der Kapselung. Und nichts gegen Helper, aber die Klasse ist damit dann auch nicht mehr ganz unabhängig von dieser und später anderen Hilfsfunktionen. Für Polymorphismus gilt in dem Fall das selbe: man braucht friend-Funktionen, wenn wir Parameter implizit bei Funktionsübergabe in ein Objekt des Typs eines Klassentemplate konvertieren wollen. Oder wir nehmen kein friend, erstellen aber getter, die machen die Kapselung aber genauso etwas schwammiger. Nicht so dolle für strenge OOPler.

    2. Statische Polymorphie benötigt man nur in der Bibliotheksentwicklung

    Da in modernen Programmen ja so gut wie alles vom Input abhängt, ist an Kompilierzeit-Polymorphismus ja gar nicht zu denken. Entwickelt man hingegen eine Bibliothek, ist der Kunde ja nicht der Benutzer, sondern der Programmierer, der seinen statischen Code niederschreibt und kompiliert. Er wird dynamische Polymorphie verwenden, weil sein Kunde der User ist, aber unsere statische Bibliothek wird immer statisch bleiben und holt damit Performance raus.



  • Der Name statische Polymorphie ist ungefähr so sinnvoll wie Dauer-Tiefpreis Spezial.



  • DP verändert das OOP-Prinzip von C++

    Not every problem is an object. Und richtig eingesaetzt, wird nichts veraendert oder geschwaecht. Auch dein Beispiel ist schlecht gewaehlt. Aktuell wird es so in Haskell gemacht mit type classes.

    Interfacedefinition (type class):

    class  Eq a  where
      (==), (/=)            :: a -> a -> Bool
      x /= y                =  not (x == y)
    

    Spezialisierung, konkrete Implementation:

    instance (Eq a) => Eq (Tree a) where 
      Leaf a         == Leaf b          =  a == b
      (Branch l1 r1) == (Branch l2 r2)  =  (l1==l2) && (r1==r2)
      _              == _               =  False
    

    Beispiel entnommen aus A Gentle Introduction to Haskell Kapitel 5, um Baume zu vergleichen. Kurze Erklaerung: um zwei Baeume vergleichen zu koennen, fordere ich nur, dass die Elemente in den Blattknoten vergleichbar sind und definiere dementsprechend meine Gleichheit fuer Baeume (rekursiv).

    Friend bröckelt etwas an der Kapselung.

    Do friends violate encapsulation?

    PS: Ich musste auch erst ueberlegen, was mit statischer Polymorphie gemeint ist. Wie kann etwas "Vielgestaltigkeit" sein, wenn es doch statisch ist? 🙂


Anmelden zum Antworten