Я использую C ++ 11. У меня есть N исходных файлов, каждый из которых содержит класс, который наследуется от общего базового класса. При запуске я хочу, чтобы каждый класс регистрировал себя в коллекции. Регистрация должна включать 1) данные, необходимые для определения цели класса, 2) фабрику классов для создания экземпляров класса. Количество исходных файлов неизвестно. Какой шаблон для этого? Решение должно быть кроссплатформенным, совместимым с Visual Studio 2013, gcc и другими.
Перво-наперво: имейте в виду, что это возможно только в том случае, если классы являются производными от одного базового класса, поскольку вы можете хранить только один тип объекта на vector
пример.
И когда дело доходит до решения … вы можете объявить объект в соответствующем файле * .cpp (отметить его extern в файле * .h):
// SomeClass.h
// <-- class declaration goes here
extern SomeClass someObj;
// SomeClass.cpp
SomeClass someObj;
И добавьте его в вектор внутри конструктора:
SomeClass(){
myVector.push_back(*this);
}
Обратите внимание, что myVector
должен быть виден в этой области.
Ваш myVector
должны быть заполнены после включения SomeClass.h
файл с одним экземпляром SomeClass
, Обратите внимание, что если заполнение выполняется в базовом классе, вам не нужно делать это в каждом последующем дочернем классе, потому что базовый конструктор вызывается в любом случае.
Звучит как Шаблон наблюдателя. Может быть лучше шаблон в зависимости от того, что вы хотите сделать с этим списком классов.
Перекрестная совместимость будет полностью зависеть от вашей реализации, но не должна создавать проблем.
Используя предложение @ Pawel, я создал пример. Цель состоит в том, чтобы создать процесс регистрации, который собирает список классов, каждая регистрация имеет фабрику классов и произвольные данные. В частности, этот пример регистрирует классы Mime в std :: map. Запись регистрации содержит вектор строк типа контента и фабрику классов для создания класса Mime.
В каждом исходном файле я использую один вкладыш для регистрации класса. Вектор типов содержимого передается для указания поддерживаемых типов класса. Каждый класс наследуется от базового класса с именем Mime (не показан).
RegisterTypes<Swagger> swagger(vector<const char *>({ "application/swagger+json" }));
В заголовочном файле определите структуру, которая будет содержать регистрационную запись. Необходимы два инициализатора, вектор типов контента и фабрика классов (реализованная как лямда).
struct Registry
{
public:
Registry() {} // initializer below forces this initializer to be needed
Registry(vector<const char *> ct, function<Mime*(void)> cf) : contentTypes(ct), classFactory(cf) {}
vector<const char *> contentTypes;
function<Mime*(void)> classFactory;
};
В заголовочном файле extern a std :: map, который будет содержать регистрации. Каждая запись на карте состоит из ключа и структуры регистрации. Фактическое определение находится в файле .cpp (не показан). Реестр использует структуру, поэтому он может содержать несколько значений.
extern std::map<const string, struct Registry> Mimes;
В заголовочном файле определите класс регистрации. Каждый экземпляр класса регистрации создает запись регистрации в std :: map. В этом примере класс регистрации создает запись регистрации, состоящую из ключа (имени класса), вектора поддерживаемых типов контента и фабрики классов. Фабрика классов создает экземпляры класса и реализуется как лямда. Каждый зарегистрированный класс имеет общий базовый класс Mime.
template<class T> class RegisterTypes
{
public:
RegisterTypes(vector<const char *> contentTypes)
{
Mimes[typeid(T).name()] = { contentTypes, [](void) -> Mime * { return (Mime *)(new T()); } }; // requires a matching explicit initializer
}
};