Как делить разные объекты между некоторыми классами - PullRequest
3 голосов
/ 02 апреля 2012

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

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

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

Ответы [ 4 ]

2 голосов
/ 02 апреля 2012

Из вашего уточнения:

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&&, которая также устраняет эту копию)

1 голос
/ 02 апреля 2012

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

1 голос
/ 02 апреля 2012

Я бы предложил, чтобы все классы, которые вы должны зарегистрировать, имели общий супертип. Например, если вам нужно хранить экземпляры классов 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 вопрос , вы можете объявить A<Object*>.

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

0 голосов
/ 02 апреля 2012

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

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