Классы проектирования для "двумерного" расширения, подобного наследованию - PullRequest
0 голосов
/ 22 июля 2011

Я хотел бы создать два базовых класса (например, рисунок и движение) с несколькими дочерними элементами для каждого (куб, сфера и т. Д. Для фигуры; сдвиг, поворот, масштабирование и т. Д. Для ходов).Начальное количество фигур и ходов неизвестно - оно должно быть расширяемым.Каждый ход должен знать, как двигать каждую фигуру, поэтому наличие N фигур и M ходов означает, что для них должна быть N * M функция.(Добавление хода требует создания N функций для каждого уже существующего рисунка, а добавление рисунка требует создания M функций для каждого уже существующего рисунка).

Вопрос в том, как объявить эти функции?Например, у меня будет класс Set, содержащий список фигур (он же вектор), и мне нужно попросить этот класс переместить все фигуры на i-й ход.Вероятно, set будет иметь метод

set::move_all (const move& ) 

и ... что дальше?Самая простая идея - создать виртуальный метод

class figure { 
    ...
    virtual void move_this (const move& ) 
    ...
}

для вызова виртуального метода1014 * и так далее, но виртуальные шаблоны недопустимы.

Ответы [ 2 ]

1 голос
/ 23 июля 2011

Вы делаете вещи сложнее, чем нужно.У вас есть коллекция объектов (которую вы называете figures) и коллекция действий (которую вы называете moves).Очевидный выбор с точки зрения ООП состоит в том, чтобы сделать moves методы в ваших figures классах.

Обновление

Исходя из комментария ниже, вы должны бытьиспользуя библиотеку линейной алгебры, такую ​​как boost::ublas.Также есть и другие, которые вы, возможно, захотите рассмотреть, такие как Eigen (более или менее показанный ниже).

Основная идея состоит в том, чтобы абстрагировать как фигуры, так и шаги, чтобы обобщить обапоэтому вам не нужно переписывать код для каждой возможной комбинации.Таким образом, вы бы создали базовый класс, который будет выглядеть примерно так:

template <typename T> class figure
{
    std::vector<Eigen::Vector3d<T> > point_list;
    ...

    void applyTransform(const Eigen::Affine3d<T>& src)
    {
       for (auto pt=point_list.begin(); pt != point_list.end(); pt++)
           (*pt) = src * (*pt);
    }
}

В этом случае вы определяете список точек на основе фигуры, которую вы визуализируете.Вы можете настроить значение точек в ваших производных классах, чтобы определить конкретные геометрические фигуры, которые вас интересуют. Класс Eigen::Affine3D используется для определения преобразований, которые вы хотите применить.В Eigen уже определены вращения и другие аффинные преобразования, поэтому вы можете использовать их повторно.

Вы также можете взглянуть на некоторые специализированные классы геометрии OpenGL или DirectX, которые делают все это за вас.

0 голосов
/ 09 сентября 2011

Что ж, мое текущее решение состоит в том, чтобы использовать typeid / typeinfo для определения пары фигур / перемещений и вызова соответствующей функции (не являющейся членом) для перемещения фигур этим перемещением из глобального объекта типа карты, подобного этому

typedef pair<string, string> fm_pair_t;
typedef figure (*fm_act_f) (const figure& F, const move& M);
map<fm_pair_r, fm_act_f> global_fm_map;

class move {
   ...
   figure move_figure (const figure& F) const
     {map<fm_pair_r, fm_act_f>::const_iterator i = 
          global_fm_map.find (fm_pair_t(typeid(F).name(), typeid(*this).name()));
      if (i == global_fm_map.end()) return F;
      return i->second (F, *this);
     }
   ...
};

и где-то

figure cube_shift (const figure& _F, const move& _M)
   {const cube& F = *dynamic_cast <const cube*> (&F);
    const shift& M = *dynamic_cast <const shift*> (&M);

    // act here with F and M like normal instances of cube and shift!

   };

и, конечно же,

global_fm_map(typeid(cube).name(), typeid(shift).name()) = cube_shift;

так что в отличие от случая использования шаблонов, все является независимым и хорошо расширяемым.

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