переменная, представляющая тип? наследование во время выполнения? - PullRequest
1 голос
/ 21 июня 2011

Моя причина задать вопрос: Я использую большой фреймворк не моего собственного дизайна. Мне нужно использовать несколько классов «пользовательской информации», которые не связаны с кодом. Они не являются производными от какого-либо общего базового класса, и у меня нет доступа к исходному коду для перекомпиляции.

Эти информационные классы работают следующим образом: есть классы A, B, C и т. Д. Каждый из этих классов имеет связанный с ними информационный класс Ainfo, Binfo и т. Д. Поскольку пользователь (то есть я) должен прикрепить различную информацию к данному объекту данного класса (имеется в виду, что у меня могут быть два разных класса, производных от Ainfo, которые я хочу присоединить к объекту A), и существует только один информационный слот Я хочу сделать информационный объект, который может устаревать другие различные информационные объекты. Таким образом, я могу просто добавить свою информацию в эти поддельные информационные объекты, которые являются контейнером для других информационных объектов.

Проблема возникает в том, что я хотел бы сделать это для Ainfo, Binfo, Cinfo, Dinfo и т. Д. Поэтому я хотел бы написать миксин или что-то, что просто добавляет функциональность контейнера к любому из простых старых информационных классов.

Проблема в том, что для информационных классов Ainfo, Binfo и т. Д. Требуются разные аргументы конструктора.

Итак, вопрос:

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

или

Можно ли наследовать от конкретного объекта? Могу ли я, например, создать новый объект Ainfo с использованием правильного конструктора, а затем выполнить миксин для этого конкретного объекта. Это было бы похоже на использование шаблона декоратора, за исключением того, что у меня нет общего интерфейса. (декорируемый объект - это интерфейс)

или

Мне просто нужно прикусить пулю и написать 15 000 (преувеличение :)) классов, которые абсолютно одинаковы, но наследуются от другого базового класса и содержат объект другого типа?

Резюме:

Мне нужно добавить функцию контейнера для нескольких различных классов, сохраняя интерфейс каждого класса и используя их конструкторы, принимающие аргументы. Я не хотел бы дублировать код.

Заранее спасибо. Извините за полную резню терминологии.

Ответы [ 3 ]

2 голосов
/ 21 июня 2011

Для меня это звучит как Boost.Variant . Это как союз в стиле C ++. Он строго типизирован (так что вы всегда знаете, что на самом деле в нем хранится), и у него есть мощный механизм посещения, который позволяет легко сопоставить множество различных типов в одной операции.

Например, вы можете сделать это:

typedef boost::variant<Ainfo, Binfo, Cinfo> CommonInfo;

//In a function.
CommonInfo someInfo = Ainfo();

Затем можно написать функторы посетителей, которые можно использовать для вызова членов информационных объектов.

class DoThingInfoVisitor : boost::static_visitor<>
{
    void operator()(Ainfo &info) {info.DoThing()}
    void operator()(Binfo &info) {info.DoThing2()}
    void operator()(Cinfo &info) {info.StepA(); info.StepB();}
};

Вооружившись этим объектом, если вы хотите сделать все, что этот DoThing означает для любого CommonInfo типа:

CommonInfo someInfo = Ainfo();
boost::apply_visitor( times_two_visitor(), someInfo );

Это вызовет версию Ainfo, поскольку именно это хранится в someInfo. Если бы он хранил Binfo, то вы можете использовать это. Вы можете построить набор из этих посетителей; они могут возвращать значения, принимать параметры (хотя вам необходимо сохранить их в функторе) и различные другие приемы, которые вы можете узнать из документации.

1 голос
/ 21 июня 2011

Это может быть немного упрощением, но если ничего другого, это должно помочь прояснить ваш вопрос. Используя шаблоны, вы можете легко создавать классы, которые являются производными от ваших информационных классов. Следующие классы иллюстрируют эту концепцию.

class Ainfo {
  std::string _a;
public:
  void setContent(const std::string& A);
  const char * print() const; // prints _a
};

class Binfo {
  std::string _b;
public:
  void setContent(const std::string& B);
  const char * print() const; // prints _b
};

template<class Tinfo>
class Info : public Tinfo {
};

Вы можете использовать этот шаблон следующим образом.

Info<Ainfo> my_info;
my_info.setContent("test");
std::cout << my_info.print();

ОБНОВЛЕНИЕ: Если вы также хотите переопределить конструктор шаблона, попробуйте использовать шаблон элемента.

template<class Tinfo>
class Info : public Tinfo {
public:
    template<typename arg>
    Info(arg rhs) : Tinfo(rhs) { }
};

Используя это, вы можете скомпилировать и запустить следующее.

Info<Ainfo> my_info("Testing...");
std::cout << my_info.print();

Я могу ошибаться, но у меня такое ощущение, что мы уже довольно близко ...

1 голос
/ 21 июня 2011

Если это невозможно в шаблонах, и вы не можете взломать его с помощью препроцессора, то вам придется делать это вручную.C ++ не содержит никаких манипуляций с типами во время выполнения, typeid() и dynamic_cast - это все, что у вас есть.

...