LINUX.ORG.RU

Хочу здоровый такой factory

 , ,


0

2

Судьба занесла писать на C++, а делаю я это редко, поэтому хорошая мысля не приходит...

есть 100-200 C++ классов с конструкторами с разными параметрами. есть XML с списком классов и параметров вызова конструкторов. нужно изобразить массив иэ объектов, указанных в XML (с соответствующими параметрами..

class BaseClass {
...
};

class Obj1: public BaseClass {
...
    Obj1(float a, float b);
};

class Obj2: public BaseClass {
...
    Obj2(char *t1);
};

class NodeList {
...
    static std::vector<BaseClass *> objs; 
};

Вот этот вот ctors надо заполнить с помошью XML

<nodes>
<node type="Obj1">
<param name="a" value="1.66"/>
<param name="b" value="2.1"/>
</node>
<node type="Obj2">
<param name="t1" value="test"/>
</node>
</nodes>

Отложив в сторону детали парсинга и прочего - какая архитектура должна быть чтобы при сотнях-тысячах объектов без труда добавлять ещё?

★★★★

Ничего не понятно. Вам нужно заполнить вектор объектами на основе XML?

static std::vector

Зачем тут static?

char *t1

Зачем сишка? Есть std::string.

BaseClass *

Сырые указатели - зло.

RazrFalcon ★★ ()
Ответ на: комментарий от RazrFalcon

Это ad-hoc пример, детали не важны.

Есть сотня классов, есть XML, надо по нему заполнять Nodelist::objs. Хочется найти оптимальный подход к задаче.

Да, в objs - инстансы объектов.

slapin ★★★★ ()
Последнее исправление: slapin (всего исправлений: 2)
Ответ на: комментарий от Midael

Почти.

Тут просто переход от парсера XML на awk и динамического кода, который постоянно ломается. По сути это дерево узлов параметров, но это для задачи не важно.

slapin ★★★★ ()

Я в подобных задачах делаю мапу фабрик:

typedef BaseClass* (*ObjFactory)(const XMLNode &n);
// ....
static std::map<std::string, ObjFactory*> FactoryMap;

Далее либо при декларации/описании классов (поможет макрос) регистрируем их фабрики (обычно статические методы самих классов), либо делаем отдельный класс/метод который регестрирует ВСЕ фабрики (либо часть так / часть так).

При парсинге делаем чтото типа:

auto it = FactoryMap.find( node.type );
BaseClass *b = it->second(node);

zaz ★★★ ()
Ответ на: комментарий от RazrFalcon

static нужен чтоб один экземпляр был. Сишка местами потому что embedded и сишка. Сырые указатели тут пофиг, так как оно один раз построится, потом живёт вечно.

slapin ★★★★ ()
Ответ на: комментарий от zaz

А как описывается регистрация вместе с декларированием класса? нет ли примера? Просто параметры у конструкторов разные, нет ли какой хитрости, чтобы меньше одинакового кода писать?

Остальное я понял, очень хороший для меня вариант, спасибо!

slapin ★★★★ ()
Ответ на: комментарий от slapin

Ну тут уже может быть много вариантов (в зависимости от конкретного случая, компилятора и тд). Как правило в этом помогает:

__attribute__((constructor)) - для вызова статической функции при запуске програмы

Шаблоны (можете посмотреть на boost::function и boost::bind) - там какраз решается много проблем с переменым количеством аргументов

Ну и макросы со всякими ## и __VA_ARGS__ для работы с произвольным количеством аргументов.

zaz ★★★ ()
Ответ на: комментарий от zaz

__attribute__((constructor))

Я понимаю надобность этого в C. Но в C++ это уже можно сделать стандартными способами:

#include <iostream>
using namespace std;

struct Abc {
  Abc() {
    cout << "Abc\n";
  }
} abc;

int main() {
  cout << "main\n";
}

напечатает:

Abc
main

i-rinat ★★★★★ ()
Ответ на: комментарий от i-rinat

Это уже дело вкуса, я не любитель плодить не используемых глобальных переменных, если их сделать static то можно получить ругань от компилятора (unused static variable), а при оптимизации (часто VC) он вообще их выкидывает и конструктор не отрабатывает ...

zaz ★★★ ()
Ответ на: комментарий от zaz

получить ругань от компилятора (unused static variable)

Это вряд ли, ведь на самом деле переменная используется — у неё вызывается конструктор. GCC, например, не ругается. Если сделать структуру простой структурой, то ругаться начнёт.

i-rinat ★★★★★ ()

на C++ рефлексию не вводили. Поэтому asm + calling convention должны помочь.

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

dzidzitop ()
Последнее исправление: dzidzitop (всего исправлений: 2)

Ну и, типа как выше уже предлагали, для N заранее известных типов - сделать так, чтобы конструктор принимал Node и сам решал как ему создавать инстанс на основе содержимого Node. Но это черезжопный метод и только если все N типов в твоём владении. А если не все типы твои - то городи вместо такого конструктора такой же Factory с развестистой иерархией.

А лучше вместо «гибкой» хмлины придумай что-нибудь, что позволит не городить тонны кода для обслуживания этой явно не необходимой гибкости.

dzidzitop ()
Последнее исправление: dzidzitop (всего исправлений: 1)