Statische versus dynamische Polymorpie
-
Artchi schrieb:
In MCD waren noch viel mehr Beispiele und Patterns (die deutlicher komplexer waren!), wo ich am Ende nichts mit in der Praxis anfangen konnte.
Ich habe mit dem Buch das gleiche Problem. Es zeigte interessante Ansätze, aber bei einem Großteil habe ich nach längeren Nachdenken kein Anwendungsszenario gefunden (Obwohl ich teilweise im ersten Moment meinte eins gefunden zu haben).
cu André
-
Artchi schrieb:
OK,
vector<T>
wird zur Compilezeit mit einem bestimmten Typen gebaut. Hem... ja... ist mir ehrlich gesagt zu trivial für Polymorphie!Im ernst, wenn DAS die ganze Story war... dann weiß ich nicht, warum ich "Modernes C++ Design" (MCD) lesen muß?
Ja. Das wird nur statische Polymorphie genannt, damit es toll klingt. Ich frag mich ja, ob die 0.5 und foo.bar() auch noch Punktpolymorphie nennen.
-
dynamische Polymorphie:
void assign_elements(container_base const& source, container_base& target) { const_iterator source_iter(source.create_first()); iterator target_iter(source.create_last()); while (!(source.is_end(source) || target.is_end(target_iter))) { *target_iter = *source_iter; ++target_iter; ++source_iter; } }
statische Polymorphie:
template <typename SourceT, typename TargetT> void assign_elements(SourceT& source, TargetT& target) { typedef typename SourceT::const_iterator source_iter_t; typedef typename TargetT::iterator target_iter_t; source_iter_t source_begin(source.end()); source_iter_t source_end(source.end()); target_iter_t target_begin(target.end()); target_iter_t target_end(target.end()); while (source_begin != source_end && target_begin != target_end) { *target_iter = *source_iter; ++target_iter; ++source_iter; } }
Beide Algorithmen schreibe ich einmal und kann sie dann auf Typen anwenden, die bestimmt Vorraussetungen erfüllen. Das ist im ersten Beispiel, von der Klasse container_base erben, im zweiten Beispiel das implizite Container-Interface. Aber technische Details sollten nicht die Theorie beeinflussen. Ich kann mir dynamische Polymorphie auch als "stumpfe" Typersetzung zur Laufzeit vorstellen. Trotzem bleibt es Polymorphie. Genauso sehe ich das im Template-Fall: Technisch ist es stumpfe Typersetzung (na ja, ob das alles so stumpf ist...). Abstrahiert nenn ich es Polymorphie.
-
Don06 schrieb:
dynamische Polymorphie:
void assign_elements(container_base const& source, container_base& target) { const_iterator source_iter(source.create_first()); iterator target_iter(source.create_last()); while (!(source.is_end(source) || target.is_end(target_iter))) { *target_iter = *source_iter; ++target_iter; ++source_iter; } }
statische Polymorphie:
template <typename SourceT, typename TargetT> void assign_elements(SourceT& source, TargetT& target) { typedef typename SourceT::const_iterator source_iter_t; typedef typename TargetT::iterator target_iter_t; source_iter_t source_begin(source.end()); source_iter_t source_end(source.end()); target_iter_t target_begin(target.end()); target_iter_t target_end(target.end()); while (source_begin != source_end && target_begin != target_end) { *target_iter = *source_iter; ++target_iter; ++source_iter; } }
Beide Algorithmen schreibe ich einmal und kann sie dann auf Typen anwenden, die bestimmt Vorraussetungen erfüllen. Das ist im ersten Beispiel, von der Klasse container_base erben, im zweiten Beispiel das implizite Container-Interface. Aber technische Details sollten nicht die Theorie beeinflussen. Ich kann mir dynamische Polymorphie auch als "stumpfe" Typersetzung zur Laufzeit vorstellen. Trotzem bleibt es Polymorphie. Genauso sehe ich das im Template-Fall: Technisch ist es stumpfe Typersetzung (na ja, ob das alles so stumpf ist...). Abstrahiert nenn ich es Polymorphie.
wäre der code identisch, wenn man das neue auto benutzte?
-
volkard schrieb:
wäre der code identisch, wenn man das neue auto benutzte?
Probleme sehe ich da bei der dynamischen Polymorphie. Da
container_base
nicht wissen kann, wie ein Iterator aussieht, habe ich eine RAII-Wrapper Klasse const_/iterator, welche als Konstruktorparameter einen Zeiger aufiterator_base
nimmt, eingeführt. Das Prblem sind also die polymorphen Iteratoren, da man sie dynamisch anlegen muss. Dann muss man sich aber wieder manuell um die Speicherfreigabe kümmern... Sollte auch nur eine Gedankenskizze sein, um die Ähnlichkeiten beider Verfahren zu zeigen. Aufgrund dieser Ähnlichkeiten ist der Name "statische Polymorphie" meiner Meinung nach vollkommen angemessen.Ich muss allerdings zugeben, dass ich deine Frage wohl nicht ganz verstehe. Ich denke mit ein paar Hilfsklassen ließe sich Code schreiben, der für beide Varianten identisch ist. Ich überleg noch einmal ein wenig.
EDIT: Man braucht nicht einmal das
auto
Schlüsselwort, um polymorphe und Standard-Container gleichzeitig zu benutzen. Ich hab mal ein Beispiel gemacht, bei dem die Elemente eines polymorphen Containers (ein gewrappter std::vector) einem normalen std::vector zugeweisen werden.template <typename SourceT, typename TargetT> void assign_elements(SourceT const& source, TargetT& target) { typedef typename SourceT::const_iterator source_iter_t; typedef typename TargetT::iterator target_iter_t; source_iter_t source_iter(source.begin()); source_iter_t source_end(source.end()); target_iter_t target_iter(target.begin()); target_iter_t target_end(target.end()); while (source_iter != source_end && target_iter != target_end) { *target_iter = *source_iter; ++target_iter; ++source_iter; } } int main() { dons::vector<int>* vector = new dons::vector<int>(); vector->push_back(1); vector->push_back(2); vector->push_back(3); std::vector<int> target; target.push_back(0); target.push_back(0); target.push_back(0); dons::container_base<int>* source = vector; // loose type information. assign_elements(*source, target); std::cout << target[0] << ", " << target[1] << ", " << target[2] << std::endl; // Ausgabe: 1, 2, 3 delete vector; // EDIT: bevor ich hier gesteinigt werde. }
Die Klasse
container_base
deklariert die Typeniterator
bzw.const_iterator
als Wrapper füriterator_base
. Der Vorteil ist, das die Template-Version jetzt auch mit den polymorphen Klassen zurechtkommt. Die Funktionassign_elements
arbeitet also je nach Kontext mit später oder früher Bindung.Gruß
Don06
-
Hi,
also ehrlich gesagt: Ich finde die Frage nach einer trennscharfen/mathematisch durchgeglühten Definition des Begriffs "Polymorphie" vergebliche Liebesmüh.
IMHO steht hinter allen Versuchen, "Polymorphie" in Programmen zu ermöglichen aus dem Wunsch nach Wiederverwendung von Code.
... und dementsprechend finde ich es deutlich sinnvoller über die Chancen und Risiken der verschiedenen Techniken zu sinnieren.Gruß,
Simon2.