2010-12-31 20 views
9

Ich versuche, einen generischen Containertyp zu erstellen, um eine einzige gemeinsame Schnittstelle bereitzustellen, und verberge die internen Container, die ich benutze, da sie sich ändern können.Generischer Container in C++

Grundsätzlich habe ich Plugins, die Sammlungen von Elementen zurückgeben, und ich möchte nicht, dass die Plugins den Typ des Containers kennen, den mein Code verwendet.

Kann mir jemand in eine bessere Richtung als der Beispielcode unten zeigen?

template<class C, typename I> 
class Container 
{ 
public: 
//... 

    void push(const I& item) 
    { 
     if(typeid(C) == typeid(std::priority_queue<I>)) 
     { 
      std::priority_queue<I>* container = (std::priority_queue<I>*)&_container; 
      container->push(item); 
     } 
     if(typeid(C) == typeid(std::list<I>)) 
     { 
      std::list<I>* container = (std::list<I>*)&_container; 
      container->push_back(item); 
     } 
     else 
     { 
      //error! 
     } 
    }; 

    private: 
    C _container; 
//... 
} 

Dank

+4

kann ich. Tu das nicht. Verbringen Sie Ihre Zeit damit, Ihre App so zu gestalten, dass sie statisch getippte Container verwendet. – ybungalobill

+1

Ich kann Sie in eine bessere Richtung weisen, sicher: ** Versuchen Sie nicht, dies zu tun **. Ernst. Es wird dir nichts bringen. Stimme der Erfahrung, die hier spricht. –

+6

Warum der Downvote hier? Es ist eine vollkommen legitime Frage. Auch wenn die Antwort lautet "mach es nicht so", war es immer noch eine gültige Frage. – Tim

Antwort

6

Ich habe Plugins, die Sammlungen von Elementen zurückgeben, und ich möchte nicht, dass die Plugins den Typ des Containers kennen, den mein Code verwendet.

Haben Sie Ihre Plugins bieten begin und end Iteratoren in ihre Sammlungen von Gegenständen und verbrauchen dann den Bereich, wie Sie für richtig halten.

Der größte Vorteil von Iteratoren ist, dass sie die vollständige Entkopplung der Daten (Container) von der Art der Datennutzung ermöglichen (der Algorithmus; in Ihrem Fall der Anwendungscode, der die Plugin-Daten verwendet).

Auf diese Weise müssen Sie sich nicht darum kümmern, wie die Plugins ihre Daten speichern, und die Plugins müssen sich nicht darum kümmern, was Sie mit ihren Daten tun, sobald sie Ihnen zur Verfügung stehen.

+0

Danke für Ihre Antworten James. Dieser Ansatz wurde untersucht, wurde jedoch haarig, wenn Threads auf der Szene erschien. Ein DataStore-Plugin kann zum Beispiel eine get_events (int validator_id) -Methode haben, die von mehreren Threads mit unterschiedlichen validator-IDs aufgerufen werden kann. – Corvusoft

+2

@user: Ich verstehe nicht; Eine Iterator-Schnittstelle hat keine Probleme mit der Parallelität mehr als eine Container-Schnittstelle: Entweder sperren Sie den Container, während Sie darüber iterieren, oder erstellen eine Kopie des Containers, um darüber zu iterieren. –

+0

+1. Aber ich denke, es wäre wünschenswert, die Notwendigkeit zu vermeiden, den Code neu zu kompilieren, der die Rückgabewerte des Plugins verbraucht, wenn ein neues Plugin erstellt wird, das intern einen anderen Containertyp verwendet - in welchem ​​Fall, wie? Es scheint, als müssten Sie die Iteratoren, die von 'begin()' und 'end()' Basisklassen (Interfaces) zurückgegeben werden, in ihre eigenen Rechte bringen und ihnen rein virtuelle 'operator ++()' und 'operator *()' geben usw. Methoden; Erstellen Sie dann für jeden verwendeten Containertyp eine konkrete Unterklasse, die an die entsprechende Methode für den richtigen Iterationstyp weiterleitet, richtig? Scheint heikel ... –

0

Wissen Sie, wenn Sie „Common Interface“ schrieb, war ich sicher, dass Sie etwas Java-Stil mit einer abstrakten Klasse und Unterklassen zeigen würden, die Standardcontainer wickeln. Ich war überrascht zu sehen, eine Reihe von Typid Anrufe ...

Aber dann, warum willst du das tun? Die meisten Container haben eine gemeinsame Schnittstelle und mit der Kraft von SFINAE müssen Sie nicht einmal einen speziellen Code schreiben! Verwenden Sie einfach Vorlagen und rufen Sie die Methode direkt auf.

BEARBEITEN: Vergessen, dass Standardcontainer keine virtuellen Methoden haben und daher nicht dynamic_cast ed sein können.

0

Beginnen Sie mit einer Klasse wie oben, und geben Sie die minimale Schnittstelle frei, die von Ihren Plugins benötigt wird. Dann implementieren Sie es in Bezug auf den Container, den Sie verwenden werden. Dies wird Containeradapter genannt und es ist wie std :: stack implementiert.

Wenn Sie wirklich Adapter für mehr als einen STL-Container benötigen, gehen Sie mit Vorlage, schauen Sie sich std :: stack an, es zeigt, wie das geht.

Schalten Sie Typid nicht ein, warum möchten Sie das?

BTW, gehen Sie mit dem, was James vorschlägt, es sei denn, es besteht die Notwendigkeit, den Container selbst zu exponieren.