001
21.10.2003, 12:43 Uhr
virtual
Sexiest Bit alive (Operator)
|
Hm,
keine Ahnung, ob ich Dich richtig verstehe. Daher nochmal so, wie ich es verstanden habe:
C++: |
class BaseContainer { virtual Iterator begin() = 0; virtual Iterator end() = 0; };
class ConcreteContainer: public BaseContainer { virtual Iterator begin(); virtual Iterator end(); };
|
Scheinbar hast Du eine Basisklasse BaseContainer. Da es ein Container ist, gibt es begin() und end(), die jeweils Iteratoren zurücklieferen. Da BaseContainer abstract ist und wir mal annehmen, begin() und end() seien dort nicht definierbar, können wir nur abstracte Methoden deklarieren. Die Klasse Iterator muß dabei aber auch in der Lage sein, mit einem ConcreteContainer zu arbeiten, weil wir ja keine covariant Returns wollen. Da Iterator aber niemals by reference zurückgegeben wird, lohnt es sich also nicht, von Iterator eine Ableitung zu machen zu machen; wir müssen also Iterator entweder direkt oder Indirekt in die lage versetzen, mit einem ConcreteContainer zu arbeiten, was aber ziemlich Problematisch wäre, weil es ja auch einen ConcreteContainer2 geben könnte, und dann müsste der auch den ConcreteContainer2 kennen... Ungefähr dieses Problem?
Dann gibt es mehrere Lösungsmöglichkeiten. Eine besteht darin, der Iterator als Proxyobject zu verwenden:
C++: |
class IteratorImpl { };
class Iterator: public std::iterator { IteratorImpl* base;
Iterator(IteratorImpl* base_) :base(base_) { }; Iterator::value_type operator * () { return *(*base); }; };
class IteratorForConcreateContainer: public IteratorImpl { ... };
class ConcreteContainer { ... Iterator begin() { return Iterator(new IteratorImp(...)); }; ... };
|
Der Nachteil ist sicherlich, daß Du da einmal mehr dereferenzieren must, ausserdem müssten alle Methoden von IteratorImpl virtuell sein. Man kann das vielleicht auch über Templates lösen:
C++: |
template<class C> class BaseContainer { typedef typename C::iterator iterator; virtual iterator begin() { return iterator(...); } // Setzt einhaitliche Constructoren voraus virtual iterator end() { return iterator (...); } // Setzt einhaitliche Constructoren voraus };
class ConcreteContainer: public BaseContainer<ConcreteContainer> { class iterator { ... }; };
|
Wenn Du die iterator Klasse in den Containern mit sinnvollen constructoren versiehst, dann kannst Du einfach nur in BaseContainer die begin/end funktionen implementieren; Der Ansatz hier hat den nachteil, daß das Binary nachher größer ist, der Vorteil ist, daß es keinen Performancenachteil gibt. -- Gruß, virtual Quote of the Month Ich eß' nur was ein Gesicht hat (Creme 21) |