У меня есть класс под названием transform
и его дочерние классы, translation
, rotation
а также scaling
, которые должны применять преобразования на треугольнике.
Каждый из дочерних классов переопределяет apply_transform()
метод:
class transform
{
protected:
virtual triangle apply_transform(const triangle&) const = 0;
public:
static triangle apply_transforms(const triangle&, const std::initializer_list<const transform*>&);
};
class scaling : public transform
{
...
public:
triangle apply_transform(const triangle&) const override;
};
//same for rotation and translation
У меня также есть функция под названием apply_transforms
, который должен быть доступен для внешнего мира, и я использую его для применения нескольких преобразований. Я передаю ему список transform*
включить полиморфизм.
Единственная проблема, которую я имею, состоит в том, что теперь дочерние классы также знают об этом методе. Это беспокоит меня, так как дочерний класс не должен быть в состоянии применить все другие преобразования.
Есть ли элегантное решение для этого?
Делать apply_transforms
функция, не являющаяся членом, которая не включена в заголовочные файлы, необходимые классам, реализующим transform
,
Я предлагаю немного изменить то, как вы видите трансформации.
Делать transform
класс такой, что для него не нужны другие классы, производные от него. Все данные, необходимые для преобразования точки, могут храниться в этом классе.
Добавьте функции, которые создают преобразование масштабирования, преобразование преобразования и вращательное преобразование.
Добавьте функции для умножения преобразований и умножения преобразования и точки. Это могут быть строительные блоки для преобразования других форм.
Добавьте функции для преобразования других фигур по мере необходимости.
В скелетной форме,
class transform { ... };
class position { ... };
// tag structs
struct rotation_about_x {};
struct rotation_about_y {};
struct rotation_about_z {};
// Functions to construct transforms
transform construct_scale_transform(double scale_factor) { ... };
transform construct_translation_transform(position pos) { ... };
transform construct_rotation_transform(double angle, rotation_about_x tag) { ... };
transform construct_rotation_transform(double angle, rotation_about_y tag) { ... };
transform construct_rotation_transform(double angle, rotation_about_z tag) { ... };
// Function to transform a point.
position operator*(transform const& t, position const& p) { ... }
// Function to multiply transforms.
transform operator*(transform const& t1, transform const& t2) { ... }// Functions to apply transforms to other objects.
triangle operator*(transform const& tr, triangle const& t) { ... }
...
Использование:
transform t1 = construct_rotation_transform(10, rotation_about_x{});
transform t2 = construct_translation_transform({20, 10, 0});
position p1{100, 200, 30};
position p2 = t1*t2*p1;
triangle tr1{ ... }
triangle tr2 = t1*t2*tr1;
Если вы собираетесь использовать одно и то же комбинированное преобразование несколько раз, сначала рассчитайте комбинированное преобразование и используйте его для всех преобразований.
transform t1 = construct_rotation_transform(10, rotation_about_x{});
transform t2 = construct_rotation_transform(5, rotation_about_y{});
transform t3 = construct_translation_transform({20, 10, 0});
tranform tc = t1 * t2 * t3;
position p1{100, 200, 30};
position p2 = tc*p1;
triangle tr1{ ... }
triangle tr2 = tc*tr1;
Дело в том, что, так как ваш apply_transforms(...)
Метод является общедоступным, он как таковой доступен для всех потенциальных абонентов. Учитывая это, вы не можете и не должны препятствовать тому, чтобы дочерние классы могли видеть эти методы.
Если вы знаете, что ваш метод будет вызываться из определенных классов, вы можете сделать его закрытым и объявить эти вызывающие классы друзьями.
В противном случае, инкапсулируйте метод в другом классе, чтобы предотвратить дочерние классы transform
от сдерживания этого.