Я хотел бы создать класс для управления матрицами, и я столкнулся с проблемой с конструктором.
Цель состоит в том, чтобы найти кратчайший способ вызвать конструктор объекта Matrix, зная, что некоторые конструкторы имеют тот же заголовок, что и оставшийся открытым.
Это идея того, что я пытаюсь получить:
Matrix id; // create identity matrix
Matrix scale(x, y, z); // create directly a scale matrix
Matrix translation(x, y, z) // create a translation matrix
...
Здесь все параметры float
Так что я не могу перегружать конструктор, я вижу только использование шаблонов, но только для тех особых случаев, тогда я не знаю, что делать.
Решение
В конце концов я решил создать абстрактный класс следующим образом:
class _Mat
{
public :
virtual ~_Mat(void) = 0;
// ...
}
class Mat : public _Mat
{
public :
Mat(void);
virtual ~Mat(void);
class Scale : public _Mat
{
public :
Scale(float x, float y, float z);
vitual ~Scale(void);
// ...
}
// ...
}
Все будет определено в _Mat
а другой класс будет просто полезен для их конструктора (ов)
Наконец, мы можем вызывать конструкторы следующим образом:
Mat id;
Mat::Scale scale(2, 2, 2);
// ...
Вы можете сделать это простым и использовать статические функции-члены:
struct Matrix
{
// ...
static Matrix Translate(float x, float y, float z) {/*...*/}
static Matrix Scale(float x, float y, float z) {/*...*/}
};
// ...
Matrix m = Matrix::Scale(1,2,3);
Ты ищешь диспетчеризация тегов. Вы можете видеть, что он используется в стандартной библиотеке, например, в перегрузках std::pair
конструктор.
Вам просто нужно объявить структуру «tag», которая используется для разрешения перегрузки:
struct translation_matrix_tag_t {} static translation_matrix_tag;
struct scale_matrix_tag_t {} static scale_matrix_tag;
А затем перегрузите ваши конструкторы:
struct Matrix {
Matrix(translation_matrix_tag_t, float, float, float);
Matrix(scale_matrix_tag_t, float, float, float);
// ...
};
Тогда вы можете использовать это так:
void foo() {
Matrix m1{translation_matrix_tag, x, y, z};
Matrix m2{scale_matrix_tag, x, y, z};
}
У вас есть следующие варианты:
Ввести разные фиктивные параметры разных типов в конструкторы, чтобы различать перегрузки. Это хак, я бы не советовал.
Используйте наследство. Создайте разные подклассы, где каждый из них будет назван в соответствии с функциональностью, предоставляемой его конструктором.
Сделайте свой конструктор частным и представьте public static
фабричные методы, которые имеют красивые и длинные имена, которые четко указывают на то, что они делают. (Без перегрузки.)
Лично я бы выбрал третий вариант.