001
05.11.2004, 11:35 Uhr
virtual
Sexiest Bit alive (Operator)
|
Vereinfacht gesagt ist eine Adaptor etwas, was ein Spezialisiertes Interface zur Verfügung stellt. zB kann Stellt ein Stack typischerweise drei zentrale Operationen zur verfügung: - Etwas auf den Stack drauf tun (push) - Das oberste Element vom Stack entfernen (pop) - Das oberste Element vom Stack auslesen (top) Daneben mag ein Stack noch andere Operationen bieten, aber belassen wir es mal dabei. Man will, daß die Operationen zur Verfügung gestellt werden, die einen Stack ausmachen, möglichst nicht wesentlich mehr. Dh. man könnte theoretisch natürlich auch direkt eine std::list oder ähnliches nehmen, nur erlaubt die list eben auch, Elemente an beliebiger Stelle zu entfernen/einzufügen, das wollen wir ja nicht.
Es leuchtet sofort ein, daß Ein Stack damit soetwas ähnliches wie ein Container ist, nämlich in dem Sinne, daß es eine potentiell beliebige Anzahl von (gleichartigen) Objekten aufnehmen kann. Nun kann man zwei Wege gehen: 1. Man programmiert für diesen Stack die Persistenz nochmal neu (also die Methoden, die notwendig sind, Objekte zu speichern) 2. Man benutzt andere Container, diesen Job zu erledigen.
Generell wird man den 2. Weg benutzen, denn man will ja Code reusen.
Nun muß man sich überlegen, wie man den Container nun benutzen will. Die Standardcontainer vector, list, deque können allesamt nicht als Basisklasse benutzt werden, dh etwas derart wie
C++: |
// VORSICHT: FALSCH! template<typename T> class stack<T>: protected std::deque<T> // protected, dh die Operationen von deque sind nicht public! { ... public: void push(const T& v) { std::deque<T>::push(v) } ... };
|
Geht nicht (weil deque eben keinen virtuelle Destructor besitzt und damit nicht ableitbar ist). Also muß man einen anderen Weg gehen, nämlich diesen hier:
C++: |
template<typename T> class stack<T>: { private: std::deque<T> c; public: void push(const T& v) { c.push_back(v) } ... };
|
Dh man macht einen Container zur Membervariablen, dieser führt nun alle relevanten Operationen durch.
Nun ist die Wahl einer deque nicht zufällig für einen Stack, denn in vielen Fällen reicht das vollkommen aus. Nur was, wenn wir - aus welchen gründen auch immer - lieber eine list benutzen würden? Neuen stack schreiben? - Nee - Wir sind ja in C++:
Alle Standardcontainer haben ein standardisiertes Interface, zB haben alle Container die push_back methode. Also definiert man den Stack mit variablen Container:
C++: |
template<typename T, class C=std::deque<T>> class stack<T>: { private: C c; public: void push(const T& v) { c.push_back(v) } ... };
|
Damit kann ich nun den Stack so aufbauen:
C++: |
stack<int> is1; // Stack von ints, der eine deque benutzt stack<int,std::deque<int>> is2; // dito stack<int,std::list<int>> is3; // Stack von ints, der eine list benutzt.
|
-- Gruß, virtual Quote of the Month Ich eß' nur was ein Gesicht hat (Creme 21) Dieser Post wurde am 05.11.2004 um 11:38 Uhr von virtual editiert. |