Как извлечь производные классы из контейнера базового класса? - PullRequest
0 голосов
/ 02 декабря 2010

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

[Tests / test0.c ++] :

int main()
{
    element wrapper;
    wrapper.name = "div";
    wrapper.attributes["id"] = "wrapper";

    cargo<string> text("Learn from yesterday, live for today, hope for tomorrow.");

    wrapper.children.push_back(&text);

    cout << "Name:\t"  << wrapper.name << endl;

         /* I have an explicit cast here,
          * but it can't be used this way
          * since children may have different types
          */
    cout << "Cargo:\t" << ((cargo< string >*) wrapper.children[0])->value << endl;

    return 0;
}

[Source / element.h]

struct element
{
    std::string name;
    std::map< std::string, std::string > attributes;
    std::vector< node* > children;
};

[Source / node.h]

struct node
{ };

[Source / cargo.h]

template <typename Type>
struct cargo
    : public node
{
    Type value;

    cargo(Type value)
        : value(value)
    { }
};

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

ОБНОВЛЕНИЕ:

Я пытаюсь создать простую структуру данных объектной модели документа, чтобы использовать ее в качестве записи таблицы символов для моего синтаксического анализатора языка, похожего на xml.Я не хочу использовать какую-либо существующую библиотеку XML, поскольку они очень большие.Я думаю, что идея DOM проста, поэтому я могу легко принять ее для некоторых более сложных операций, например, разрешив универсальные типы для узлов в дереве DOM, используя cargo<Type>.Я признаю, что дизайн, который я принял, может быть не самым адекватным!Так что я открыт для предложений!

Буду благодарен за любую помощь!

Ответы [ 5 ]

1 голос
/ 02 декабря 2010


Этот вопрос, вероятно, больше касается дизайна, чем реализации.
Хотя Boost.Variant и Boost.Any будут работать, они будут только обходным путем.Реальная проблема может заключаться в том, что переменная часть ответственности классов, полученная из класса узла, не инкапсулирована.
Вместо этого вы можете попробовать использовать композицию.Один хост-класс используется для общего интерфейса и соответствующего количества компонентов / делегатов / чего угодно (они должны быть рождены из дизайна решения :)).

Или ... вам может подойти совершенно другое решение.Вы можете рисковать мета программирования слова и угробить общий интерфейс.Вместо этого могут помочь такие сущности, как кортежи (списки типов).

С наилучшими пожеланиями,
Марчин

1 голос
/ 02 декабря 2010

Если вы не планируете полиморфически обрабатывать элементы контейнера при извлечении, Boost.Variant может быть полезно для обертывания элементов контейнера детерминированным способом.

Вариант шаблона класса является безопасным, универсальный, основанный на стеке союз контейнер, предлагая простой решение для манипулирования объектом из разнородного набора типов в единообразно Тогда как стандарт контейнеры, такие как std :: vector, могут быть мыслить как «многозначный, единый тип, "вариант есть" мульти-тип, одиночный значение ".

В этом предыдущем вопросе есть пример кода .

1 голос
/ 02 декабря 2010

если вы просто используете потоковую передачу, вы можете реализовать потоковые операторы в базовом классе, а затем делегировать их методу в производном классе, иначе посмотрите шаблон посетителя. Не имея реального представления о том, какие операции вы, вероятно, будете выполнять на cargo, трудно сделать дополнительные предложения ...

0 голосов
/ 02 декабря 2010

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

Предполагая, что это как-то невозможно, пробовали ли вы dynamic_cast?Он возвращает ноль, если приведение не выполнено, вместо броска, как будет делать ваш static_cast выше.

Надеюсь, это поможет, Бизлер

0 голосов
/ 02 декабря 2010

Без актеров не получится так.

Но самое главное, это часто означает, что вы идете не в ту сторону. До тех пор, пока вы решили, что cargo будет публично наследоваться от node, вы обеспечили очень сильные отношения между двумя классами, и «быть node» имеет гораздо более сильное значение, чем:

Я могу быть вставлен в контейнер наряду с другими node производными типами

Нам нужно знать, что такое node и что с ним можно сделать, чтобы помочь вам в дальнейшем. Однако, если вам действительно нужно придерживаться первоначального решения, вам может помочь boost.variant .

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