Iterator Klasse Postincrement
-
Hallo zusammen
Ich hab folgendes vor. Ich würde gerne das Iteratorenkonzept implementieren, also Inputiterator, Output,....
Nun habe ich abstrakte Klassen definiert, welche die notwendigen virtuellen Funktionsköpfe enthalten, und welche dann geerbt werden müssen von einem spezifischen Iterator.
Nun habe ich folgendes Problem. Den Preincrementoperator kann ich problemlos definieren.
virtual Iterator& operator++() = 0;Wie sieht es aber mit dem Postincrementoperator aus?
Dort müsste ich ja
virtual const Iterator operator++(int) = 0;schreiben. Das geht aber nicht, da meine Klasse ja abstrakt ist, und ich deshalb eine Fehlermeldung bekomme, da ja keine Instanz gebildet werden kann.
Gibt es eine elegante Lösung, oder ist es nicht möglich? Gibt es eventuell ganz andere Konzepte, um das selbe zu implementieren?
-
Einerseits würde ich mal Boost.Iterator angucken... ev. hast Du ja Boost zur Verfügung.
Konkret kann dein Problem so gelöst werden, dass Du beim Post Increment operator ein Zeiger zurückgibst, der auf eine auf dem Freestore erstellten Kopie des Iterators zeigt). Um alles noch ein weniger angenehmer zu machen, kanst Du das am besten mit Smart Pointer (std::unique_ptr<..>, std::shared_ptr<..>, falls die Klassen aus C++11 schon zur Verfügung stehen).
Die Kopie des Iterators kannst Du via Clone() Methode realisieren. Dazu verpasst Du dem Iterator Interface eine Clone() Methode, welche dann in der konkreten Iterator Klasse implementiert wird und eine Kopie (auf dem Freestore zurückgibt).
Edit:
Ungefähre Idee im Code:class Iterator { public: virtual std::unique_ptr<Iterator> clone() const = 0; virtual Iterator& operator++() = 0; std::unique_ptr<Iterator> operator++(int) { auto temp = clone(); ++(*this); retun temp; } // .. }; class IteratorImpl : public Iterator { public: virtual std::unique_ptr<Iterator> clone() const { return std::unique_ptr<Iterator>(new IteratorImpl(*this)); } virtual Iterator& operator++() { // .. increment .. return *this; } };
-
Das ist so in C++ nicht ueblich. In C++ nimmt man Templates, die einem Flexibilitaet ohne zusaetzliche Kosten (virtuelle Funktionen, Heap-Allokation) erlauben.
C++ ist nicht Java.
-
Kellerautomat schrieb:
Das ist so in C++ nicht ueblich. In C++ nimmt man Templates, die einem Flexibilitaet ohne zusaetzliche Kosten (virtuelle Funktionen, Heap-Allokation) erlauben.
C++ ist nicht Java.
Und da sind sich natürlich alle Anwender von C++ einig... es gibt Gründe warum man das genau so machen möchte (Interface, virtuelle Funktionen, Freestore ist nur eine Folge davon).
-
Wenn dem so waere, hatte man es vermutlich schon desoefteren so gemacht. Natuerlich gibts Faelle, wo sowas vlt praktisch waere, aber ich glaube nicht, dass der TE schon in der Lage ist, zu entscheiden.
-
Kellerautomat schrieb:
Wenn dem so waere, hatte man es vermutlich schon desoefteren so gemacht. Natuerlich gibts Faelle, wo sowas vlt praktisch waere, aber ich glaube nicht, dass der TE schon in der Lage ist, zu entscheiden.
Aber Du natürlich schon, besonders, da Du ja das Problem des TE so genau kennst.
-
Ich lehne mich mal so weit aus dem Fenster, um zu sagen, dass die Standard-Methode mit grosser Wahrscheinlichkeit "gut genug" ist, ja.

-
Kellerautomat schrieb:
Ich lehne mich mal so weit aus dem Fenster, um zu sagen, dass die Standard-Methode mit grosser Wahrscheinlichkeit "gut genug" ist, ja.

Ja dann ist ja
gutbestens.
-
Mal ein anderer Vorschlag: Wie wärs mit CRTP?

Dein Problem als solches ist schon die Idee. Da wirst du nicht weiter kommen. Das Problem ist mehr oder weniger, dass du eine Instanz einer abstrakten Klasse zurückgeben musst. Das geht aber nicht. Die kann nicht existieren. Also entweder Referenz/Zeiger (was du aus gutem Grund nicht willst), oder etwas anderes zurückgeben, was nicht abstrakt ist.
-
Ein Wunder, dass noch niemand geschrieben hat, der gezeigte Code sei kein C++. Ich bin zuversichtlich, dass das bald erwähnt wird...
-
Das Problem lässt sich auf folgende Klasse minimieren:
template<typename der> struct A { virtual der foo() = 0; };Mein Vorschlag:
template<typename der> struct A { virtual der foo() = 0; }; struct B : public A<B> { B foo() { return B(); } ///Wenn C++11-kompatibel, override dazu };Damit wäre das Konzept erhalten (oder?), und die Semantik korrekt.
theta schrieb:
Ein Wunder, dass noch niemand geschrieben hat, der gezeigte Code sei kein C++. Ich bin zuversichtlich, dass das bald erwähnt wird...
Na klar, wo ist denn der Konstruktor deklariert/definiert, der in Zeile 24 genutzt wird?

-
CRTP mit virtual. Ahja.
-
Edit: Näh, das ist Blödsinn.
Schließlich wird eine dynamische Bindung damit unmöglich...
-
Na theta haste zuviel Java programmiert in letzter Zeit? Deine Lösung ist absurd in C++.
-
ich bin ja gespannt, wie Kellerautomat seine templatisierten Iteratoren verwendet, wenn er late binding braucht
.Die Lösung ist, wie bereits angesprochen, ein Proxy-Objekt das von Iterator abgeleitet ist und eine temporäre Kopie des Iterators enthält, die zum Schluss zerstört wird.