2012-06-19 12 views
6

Mam klasy jak poniżej:umożliwiając dostęp do obiektów kontenerowych w C++

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

Teraz chciałbym, aby umożliwić użytkownikowi dostęp do obu zbiorów, ale ukryć szczegóły implementacji, że jestem przechowywaniu obiekty na std :: maps. Zamiast tego chciałbym mieć funkcje członkowskie, które zwracają np. iteratory const dla kolekcji i ewentualnie iterator niestandardowy, który zwraca obiekty z obu kolekcji, ponieważ Bar i Baz należą do tej samej hierarchii klas. Biorąc pod uwagę styl, jaki byłby właściwy sposób robienia tego w C++? W Javie prawdopodobnie ustawię typ powrotu metody na Iterable lub zapakuję kolekcję w UnmodifiableCollection.

+1

Jeśli używasz czegoś takiego jak ['any_iterator'] (http://thbecker.net/free_software_utilities/type_erasure_for_cpp_iterators/any_iterator.html), możesz ukryć podstawowy typ bez przeciekania szczegółów. Możesz użyć czegoś takiego jak Transform_iterator Boost lub zip_iterator również jako pośrednika, bez użycia jakichkolwiek innych narzędzi. – Flexo

Odpowiedz

1

Możesz odrzucić iteratory kolekcji jako swoje własne.

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; 
}; 

To oszczędza pracę wdrażaniu własnego iterator, ale pozostawia nam elastyczność zmieniając rodzaje kontenerów później i tylko wymagających rozmówców rekompilacji.

To nie rozwiązuje problemu iterowania ich razem.

+0

Dziękuję. Próbowałem czegoś z iteratorami Boosta, ale nie mogłem ich uruchomić, więc postanowiłem zrobić coś innego. Znalazłem tę bibliotekę, ale wygląda na to, że przez ponad dziesięć lat była pre-alpha: http://www.zib.de/weiser/vtl/ – tsnorri

1

Załóż interfejs, który ukrywa szczegóły:

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; 
}; 

Dla wszystkich użytkownik wie, można być przechowywanie ich w std :: pair wewnątrz listy, wewnątrz wektora, lub nawet za pomocą równoległych tablic. ... cokolwiek naprawdę.

EDIT:

Fakt, że jesteś przechowując je w mapie, ale chcesz użytkownik iteracyjne nad podstawowych zapachów kontenerowych złym/niewłaściwej konstrukcji. Zezwól im na dostęp indywidualny jak wyżej lub stwórz metody, które zrobią to za nich.

+0

Program OP poszukuje sposobu na powtórzenie zawartości ... –

+0

Oprócz tego, co wskazał Oli, eksponowanie iteratorów nie musi ujawniać typu bazowego. Iteratory mogą być abstrakcyjne, np. Jak wskazano powyżej. – stinky472

Powiązane problemy