2012-06-19 2 views
6

У меня есть класс, как показано ниже:Предоставление доступа к объектам контейнера в C++

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

Теперь я хотел бы разрешить пользователю доступ к обоим коллекции, но скрыть детали реализации, что я, хранящую объектов в std :: maps. Вместо этого я хотел бы иметь функции-члены, которые возвращаются, например. const итераторы для коллекций и, возможно, даже пользовательский итератор, который возвращает объекты из обеих коллекций, поскольку Bar и Baz принадлежат к одной и той же иерархии классов. Учитывая стиль, что было бы правильным способом сделать это на C++? В Java я, вероятно, установил бы тип возвращаемого метода в Iterable или обернул бы коллекцию в unmodifiableCollection.

+1

Если вы используете что-то вроде ['any_iterator'] (http://thbecker.net/free_software_utilities/type_erasure_for_cpp_iterators/any_iterator.html), вы можете скрыть базовый тип без утечки информации. Вы можете использовать что-то вроде transform_iterator или zip_iterator в качестве посредника, но без использования каких-либо мудрых. – Flexo

ответ

1

Вы можете передать итераторы коллекции как свои.

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

Это позволяет сэкономить работу реализации собственного итератора, но оставляет вам гибкость изменения ваших типов контейнеров позже и только требует звонящих перекомпилировать.

Это не решает проблему итерации их обоих вместе.

+0

Спасибо. Я пробовал что-то с итераторами Boost, но не мог заставить их работать, поэтому я решил сначала сделать что-то еще. Я также нашел эту библиотеку, но она, кажется, была pre-alpha более десяти лет: http://www.zib.de/weiser/vtl/ – tsnorri

1

Создайте интерфейс, который скрывает детали:

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

Для всех пользователь знает, вы могли бы хранить их в станд :: пара внутри списка, внутри вектора, или даже с использованием параллельных массивов. ..ничего действительно.

EDIT:

Тот факт, что вы храните его в карте, но хотите пользователь перебрать нижележащий контейнер запахами плохого/неправильного дизайна. Либо только разрешите им индивидуальный доступ, как указано выше, либо создайте методы, которые сделают это для них.

+0

OP ищет способ перебирать содержимое ... –

+0

В дополнение к тому, что указал Оли, разоблачение итераторов не должно выявлять базовый тип. Итераторы могут быть абстрактными, например, как указано выше. – stinky472

Смежные вопросы