6 Stimmen

Abstrakter Wrapper für stl-Container?

Ich möchte einige Objekte als abstrakte Container mit stl-Stil Manipulationsmöglichkeiten (for_each Schleifen, Iteratoren) und verstecken Container Implementierung Details.

Leistungsprobleme spielen keine Rolle (virtuelle Aufrufe und sogar die Speicherzuweisung beim Kopieren des "universellen" Iterators sind akzeptabel).

Ich werde eine abstrakte Container-Schnittstelle mit rein virtuellen Funktionen (+ "universal" Iterator über den Container) und eine Implementierung Adapter für stl sequentielle Container zu schreiben.

Aber vielleicht gibt es ja schon nützliche Bibliotheken für diesen Zweck?

Oder ist es eine ganz schlechte Idee?

2voto

Max Lybbert Punkte 19181

1voto

Calvin1602 Punkte 9237

Wenn es sich bei Ihren "Objekten" nicht um STL-Objekte, sondern um benutzerdefinierte Objekte handelt, halte ich das für eine gute Idee.

Wie Sie sehen können http://www.sgi.com/tech/stl/Vector.html vector "ist ein Modell von" RandomAccessContainer. Die meisten Boost-Pakete verwenden ähnliche Konzepte (der Begriff ist eigentlich "Konzept")

In C++ haben Sie zwei Möglichkeiten, dies zu tun:

  • Eine abstrakte Klasse (Schnittstelle), wie von Ihnen vorgeschlagen
  • Schablonen

Mit Vorlagen kann man so etwas machen wie :

doSomething < AnythingThatIsIterable >(AnythingThatIsIterable i){
    for (AnythingThatIsIterable::itertaor it = i.begin(); it != i.end(); ++i){
        it->foo()
    }
}
  • Jede Klasse, die einen Iterator, Anfang und Ende bereitstellt, funktioniert: std::vector, aber auch Ihre eigenen Objekte.
  • Diese Objekte müssen nicht von einer Schnittstelle erben, so dass std::vector wird Arbeit.

1voto

Basilevs Punkte 20145

Hier ist meine Vorwärts-Iterator-Wrapper für Java-Stil implementiert ein. Es ist hässlich. Boost-Teile sind optional und könnten heraus refactored werden.

0voto

pyon Punkte 18048

Die allgemeinste Lösung für das Problem, eine C++-Klasse so darzustellen, dass die Benutzer der Klasse ihre Programme nicht neu kompilieren müssen, wenn sich meine Implementierung der Klasse ändert, ist das pImpl-Muster. Für mehr Informationen: http://en.wikipedia.org/wiki/Opaque_pointer

0voto

AJ S. Punkte 400

Ich verstehe die Frage des Benutzers vollkommen. Er/sie möchte eine benutzerdefinierte Containerklasse, die dem Benutzer eine STL-ähnliche Schnittstelle zur Verfügung stellt. Die Standard-STL-Container reichen in gewisser Weise nicht aus und sind daher keine geeignete Wahl.

Ich habe zum Beispiel eine Schnittstellenklasse für eine 'Dataline' namens IDataline. Eine Implementierung der IDataLine-Schnittstelle nimmt bei der Konstruktion eine begrenzte Zeichenkette, parst sie und gibt die Liste der Felder über einen const_iterator mit forward_iterator_tag-Semantik aus. Kein STL-Container kann dies von Haus aus tun.

Außerdem möchte meine Kundenklasse in der Lage sein, durch zwei Datenzeilenfelder zu iterieren und sie Feld für Feld zu vergleichen.

Ich habe die IDataline-Schnittstelle wie folgt definiert:

 1 class IDataline
 2 {
 3 public:
 4    class const_iterator 
 5    {
 6      public: 
 7           virtual const_iterator& operator=(const const_iterator& rhs) =0;
 8           virtual bool operator==(const const_iterator& rhs) =0;
 9           virtual bool operator!=(const const_iterator& rhs) =0;
10           virtual const_iterator& operator++() =0;
11           virtual const_iterator  operator++(int) =0;
12           virtual const Field& operator*() =0;
13           virtual const Field* operator->() =0;
14           virtual const Field& operator[](size_t idx) =0;
15           virtual size_t offset() =0;
16    }; 
17
18    virtual const_iterator begin() =0;
19    virtual const_iterator end() = 0;
20 };

Das Problem ist in den Zeilen 11, 18 und 19 zu sehen - wir müssen in der Lage sein, einen const_iterator zurückzugeben, was einen Kopierkonstruktor erfordert, aber da es sich um eine virtuelle Schnittstelle handelt, gibt es weder einen Standard- noch einen Kopierkonstruktor (für den Schnittstellentyp), und der Compiler versagt (ordnungsgemäß).

Sie könnten argumentieren, dass ich begin() und end() als definieren könnte:

virtual const_iterator& begin() = 0;
virtual const_iterator& end() = 0;

Dann kann ich zwei Instanzen des spezialisierten Iterators im spezialisierten Host erstellen und Referenzen (oder Zeiger für diejenigen, die diese bevorzugen) zurückgeben, um dies für meinen Fall zu erreichen.

Das Problem ist, dass eine solche Implementierung nicht alle Anforderungen für Vorwärts-Iteratoren erfüllt und in allgemeineren Anwendungsfällen, die auf die Semantik von Vorwärts-Iteratoren angewiesen sind, nicht funktioniert.

Nach einigem Nachdenken (und der Beratung durch einen Kollegen) bin ich auf zwei Möglichkeiten gestoßen, wie dieses Problem gelöst werden kann:

  1. Muss Ihre Gastgeberklasse sein vollständig abstrakt? Wenn Sie die Abstraktion auf das Verhalten beschränken können, das Sie variieren müssen, dann kann Ihr instanziierbarer Host einen konkreten Iterator einbetten (weil eine Instanz der Klasse selbst instanziiert werden kann) und Sie haben, was Sie brauchen.

  2. Eduardo Leon zeigt an, dass der Iterator selbst mit dem Idiom pimpl (Pointer to an implementation) umhüllt werden kann. Es gibt zwar eine Menge Material, das diese Technik ausführlich beschreibt, Basilev , in den Kommentaren unten Leons deutet darauf hin, dass er nicht glaubt, dass das Idiom pimpl funktionieren wird. Mein Kollege bot mir eine Technik zum Ausprobieren an, also werde ich ein Testmuster ausarbeiten. Wenn es funktioniert, werde ich es teilen. Wenn nicht, werde ich die Erfahrungen, die ich mit dem Beispiel gemacht habe, detailliert beschreiben und darauf warten, dass jemand, der mehr Erfahrung hat, sich dazu äußert, ob pimpl in diesem Fall anwendbar ist oder nicht.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X