2012-06-19 12 views
6

ich eine Klasse wie unten haben:Zulassen des Zugriffs auf Containerobjekte in C++

class Foo { 
private: 
    std::map<std::string, Bar*> bars_by_name; 
    std::map<std::string, Baz*> bazs_by_name; 
}; 

Nun möchte Ich mag, damit der Benutzer beide Sammlungen zugreifen, aber die Umsetzung Detail verbergen, dass ich das bin Speichern Objekte in std :: maps. Stattdessen möchte ich Memberfunktionen haben, die z. Const Iteratoren für die Sammlungen und möglicherweise sogar einen benutzerdefinierten Iterator, der Objekte aus beiden Sammlungen zurückgibt, da Bar und Baz zu derselben Klassenhierarchie gehören. Was wäre der richtige Weg, dies in C++ zu tun? In Java würde ich wahrscheinlich den Rückgabetyp der Methode auf Iterable setzen oder die Sammlung in eine unmodifizierbare Sammlung umbrechen.

+1

Wenn Sie etwas wie ['any_iterator'] (http://thbecker.net/free_software_utilities/type_erasure_for_cpp_iterators/any_iterator.html) verwenden, können Sie den zugrunde liegenden Typ verbergen, ohne Details zu verlieren. Sie können auch etwas wie Boosts transform_iterator oder zip_iterator als Vermittler verwenden, ohne dass Sie sich dafür interessieren. – Flexo

Antwort

1

Sie könnten die Iteratoren der Sammlung als Ihre eigenen übergeben.

class Foo { 
    private: 
    typedef std::map<std::string, Bar*> BarContainer; 
    typedef std::map<std::string, Baz*> BazContainer; 
    public: 
    typedef BarContainer::const_iterator ConstBarIterator; 
    ConstBarIterator beginBars() { return bars_by_name.cbegin(); } 
    ConstBarIterator endBars() { return bars_by_name.cend(); } 
    typedef BazContainer::const_iterator ConstBazIterator; 
    ConstBazIterator beginBazs() { return bazs_by_name.cbegin(); } 
    ConstBazIterator endBazs() { return bazs_by_name.cend(); } 

    private: 
    BarContainer bars_by_name; 
    BazContainer bazs_by_name; 
}; 

Dies erspart Ihnen die Arbeit der eigenen Iterator Umsetzung noch lässt Sie die Flexibilität, Ihre Containertypen später ändern und nur erfordern Anrufer neu zu kompilieren.

Es löst nicht das Problem der Iteration sie beide zusammen.

+0

Vielen Dank. Ich habe etwas mit Boosts Iteratoren versucht, aber ich konnte sie nicht zum Laufen bringen, also entschied ich mich, zuerst etwas anderes zu machen. Ich habe diese Bibliothek auch gefunden, aber sie scheint seit über zehn Jahren Pre-Alpha zu sein: http://www.zib.de/weiser/vtl/ – tsnorri

1

eine Schnittstelle erstellen, die die Details versteckt:

class Foo { 
    public: 
     void AddBar(std::string name, Bar*); 
     void RemoveBar(std::string name); 

     Bar* GetBar(std::string name); 
     Bar* GetBar(std::string name) const; 

     void AddBaz(std::string name, Baz*); 
     void RemoveBaz(std::string name); 

     Baz* GetBaz(std::string name); 
     Baz* GetBaz(std::string name) const; 

    private: 
     std::map<std::string, Bar*> bars_by_name; 
     std::map<std::string, Baz*> bazs_by_name; 
}; 

Für alle Benutzer wissen, könnte man sich in einem std :: pair in einer Liste, in einem Vektor oder sogar unter Verwendung von parallelen Arrays werden zu speichern. ..etwas wirklich.

EDIT:

Die Tatsache, dass Sie es in einer Karte sind die Speicherung, sondern wollen, dass die Benutzer über den darunter liegenden Behälter Gerüche eines schlecht/falsch Design iterieren. Entweder erlaube ihnen nur individuellen Zugriff wie oben oder erstelle Methoden, die das für sie tun.

+0

Das OP sucht nach einer Möglichkeit, über den Inhalt zu iterieren ... –

+0

Zusätzlich zu dem, worauf Oli hingewiesen hat, muss das Aussetzen von Iteratoren den zugrunde liegenden Typ nicht offen legen. Die Iteratoren könnten abstrakt sein, beispielsweise wie der oben angegebene any_iterator. – stinky472

Verwandte Themen