Совместимость классов с разными владельцами - PullRequest
0 голосов
/ 28 марта 2011

Учитывая :

class Foo1 { 
 public:
  typedef Foo2 owner;
};
class Foo2 {
 public:
  typedef Foo1 vassal;
  typedef Foo3 owner;
};
//... and so on 
class FooN {
 public:
  typedef FooNm1 vassal;
  typedef ExternalType owner;  // problem
  owner* owner();
};

Вопрос:

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

Проблемы :

  1. Если мы сделаем FooN шаблоном с владельцем в качестве параметра шаблона, то каждый класс иерархии Foo {N} будет заражен этим владельцем через цепочку зависимостей.
  2. Если мы создадим интерфейс FooNOwner для наследования от внешнего владельца, то мы столкнемся с необходимостью динамического приведения, чтобы перейти от алгоритмов в иерархии Foo {N} к фактическому владельцу.1019 * Существует ли шаблон проектирования для решения моей проблемы?

    Пример ситуации, когда возникают эти проблемы: у вас есть структура, состоящая из классов Foo {N}.Он используется для быстрого поиска, и запрос из него возвращает список объектов Foo {N}.Я хочу получить указатель конкретного типа ExternalOwner * на внешнего владельца из возвращенного объекта FooN, чтобы избежать динамического приведения.В то же время я хочу работать с объектами Foo {N} (может быть, без FooN) с отдельным FooN :: owner без оглядки на эту разницу.

    Обновление:

    Возможно, единственный верный способ сделать это - определить общий интерфейс владельца и перегрузить его владельцами для использования в контексте, где существуют различные классы владельцев.Таким образом, этот интерфейс определяется контекстом его использования (но FooN не имеет ничего общего с контекстом использования FooN :: owner).Это проблема, которую я пытался решить изначально - отдельные задачи, этот подход мне не помогает.

    Мое решение

    Я получил двойную диспетчеризацию.Если я добавлю виртуальный void apply (FooOwnerVisitor *) = 0;Функция для FooOwner и определение интерфейса FooOwnerVisitor поблизости, тогда я могу добавить любую функциональность для производных FooOwner, не влияя на иерархию FooN и без dynamic_cast.

Ответы [ 2 ]

0 голосов
/ 29 марта 2011

Я закончил с двойной отправкой. Если я добавлю виртуальный void apply (FooOwnerVisitor *) = 0; Функция для FooOwner и определение интерфейса FooOwnerVisitor поблизости, тогда я могу добавить любую функциональность для производных FooOwner, не затрагивая иерархию FooN и без dynamic_cast. Таким образом, моя проблема на самом деле имеет две проблемы, которые имеют собственные решения. Первое - как сделать классы FooN от разных владельцев совместимыми - наследовать от интерфейса владельца. Второе - как избежать динамического приведения производных классов FooNOwner - используйте шаблон Visitor. Нужно рассмотреть возможность разделения проблемы на более мелкие и объединения атомных решений.

0 голосов
/ 28 марта 2011

Я не думаю, что кто-то четко понимает ваше требование, но это мое лучшее предположение при его рассмотрении ... иллюстрирующее, как обрабатывать то, что вы называете "цепочкой зависимостей" в шаблонном решении.Если это не помогает, но имеет какое-то отношение, объясните это, и проблемы помогут людям помочь вам.Если вы хотите применить алгоритмические циклы к объектам Foo<>, я могу проиллюстрировать, как это сделать ....

#include <iostream>

struct Abstract_Bar
{
    virtual void f() const = 0;
};

struct Bar1 : Abstract_Bar
{
    void f() const { std::cout << "Bar1\n"; }
};

struct Bar2 : Abstract_Bar
{
    void f() const { std::cout << "Bar2\n"; }
};

template <int N>
struct Foo
{
    typedef Foo<N - 1> Lower;
    typedef Foo<N + 1> Higher;

    void f() const { std::cout << "Foo<N>\n"; }

    Higher* higher_;
};

template <>
struct Foo<1>
{
    typedef Foo<2> Higher;

    void f() const { std::cout << "Foo<1>\n"; }

    Higher* higher_;
};

template <>
struct Foo<4>
{
    typedef Foo<3> Lower;
    typedef Abstract_Bar Higher;

    void f() const { std::cout << "Foo<4>\n"; }

    Higher* higher_;
};

int main()
{
    Foo<1> foo1;
    Foo<2> foo2;
    Foo<3> foo3;
    Foo<4> foo4;
    foo1.higher_ = &foo2;
    foo2.higher_ = &foo3;
    foo3.higher_ = &foo4;
    Bar1 bar1;
    foo4.higher_ = &bar1;

    foo1.f();
    foo2.f();
    foo3.f();
    foo4.f();

    foo1.higher_->f();
    foo2.higher_->f();
    foo3.higher_->f();
    foo4.higher_->f();

    // switch to another type of "Bar"...
    Bar2 bar2;
    foo4.higher_ = &bar2;
    foo4.higher_->f();
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...