2012-04-02 5 views
3

Каков наилучший способ поделиться различными объектами между некоторыми классами в общем виде?Как делиться различными объектами между некоторыми классами

Например, класс A может хранить объект o со строкой в ​​виде ключа в регистре, а класс B может получить к нему доступ с помощью ключа.

Моя первая идея состояла в том, чтобы создать регистр (singleton), который имеет хэш-таблицу в качестве члена, используя строку в качестве ключа и указатель void как значение. Но для этого должно быть лучшее решение?

+0

"generic manner" - шаблоны? 'void *' - это решение C. – MSalters

+0

@MSalters: точно. Вот почему я обратился за помощью. –

+0

По крайней мере, используйте 'boost :: any' вместо' void * '. –

ответ

2

Вашего осветления:

template <typename OB> 
class A { 
    std::unordered_map<std::string, OB> hash; 
public: 
    OB const& get(std::string const&) const; 
    void add(OB const& object, std::string const&); 
}; 

То есть, A<int> это класс, который хранит int объектов по имени, и A<std::set<float>> это класс, который хранит наборы поплавков по имени. Вы не можете их смешивать. Это соответствует основной философии C++: тип theA.get("foo") определяется во время компиляции, а не тем, что вы вводили во время выполнения.

В C++ вы можете, однако, «смешивать» несколько производных типов, если вам понадобится это для вашего конкретного случая. Это немного сложнее:

template <typename Base> 
class A { 
    std::unordered_map<std::string, std::unique_ptr<Base>> hash; 
public: 
    Base const& get(std::string const&) const; 
    template<typename Derived> void add(std::string const& name, Derived const& object) 
    { 
    std::unique_ptr<Base> copy(new Derived(object)); 
    hash.emplace(std::make_pair(name, std::move(copy))); 
    } 
}; 

Там какие-то небольшие фокусов здесь hash должен быть единственным владельцем копии, но она построена снаружи, и, следовательно, должна быть перемещен его. (Для экстра-фантазии, я мог бы добавить Derived&& перегрузку, которая устраняет эту копию тоже)

+0

Это идет в правильном направлении и уже помогло мне немного - Спасибо! Не могли бы вы также продемонстрировать свой второй подход? –

+0

@jisaak: Добавлено. – MSalters

0

Лучшим способом является использование shared_ptr, а не голый указатель. Если у вас есть компилятор, совместимый с C++ 11, shared_ptr находится в пространстве имен std. В противном случае используйте реализацию Boost.

+1

Это не отвечает на мой вопрос. –

+0

Возможно, я не понял ваш вопрос правильно. Вы действительно спрашиваете, как хранить объекты разных типов в одном контейнере? –

1

Я бы предположил, что все классы, которые вы должны зарегистрировать, имеют общий супертип. Например, если вы должны хранить экземпляры классов One, Two и Three можно определить (возможно, пустой) класс Object, из которых ваш класс может выводим:

class Object {} 
class One : public Object { /* One's member and methods */ } 
class Two : public Object { /* Two's member and methods */ } 
class Three : public Object { /* Three's member and methods */ } 

Если следовать MSalters question вы можете объявить a A<Object*>.

Если вы не можете иметь один супертип (например, потому что вы не можете изменить One, Two или Three) вы можете посмотреть на Boost.Variant. Опять же, вы можете объявить A<boost::variant<One, Two, Three> >.

1

Первый вопрос: как B знать тип хранимого объекта, и что она может делать с ним? Возможно, самое простое решение - только имеют один реестр для каждого типа. В качестве альтернативы можно использовать что-то вроде boost::variant, или вы можете гарантировать, что все типы выводят из общей базы и сохраните указатель на это. Если вы на самом деле не нуждаетесь в поддержке полиморфизма (например, работа на объекте без , зная его точный тип), я бы избежал использования указателя.

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