Ответ 1
Лучше добавить статические методы с соответствующими именами и позволить им создавать объекты.
static Complex createFromCartesian(double re, double img);
static Complex createFromPolar(double A, double w);
Предположим, что нам нужны два конструктора для класса, представляющих комплексные числа:
Complex (double re, double img) // construct from cartesian coordinates
Complex (double A, double w) // construct from polar coordinates
но параметры (число и тип) одинаковы: какой изящный способ определить, что предназначено? Добавление третьего параметра в один из конструкторов?
Лучше добавить статические методы с соответствующими именами и позволить им создавать объекты.
static Complex createFromCartesian(double re, double img);
static Complex createFromPolar(double A, double w);
У вас нет двух конструкторов (или любых функций) с теми же сигнатурами. Лучшим решением, вероятно, является создание классов для ваших типов координат и перегрузка на них. Например:
struct CartCoord {
CartCoord( double re, double img ) : mRe(re), mImg(img) {}
double mRe, mImg;
};
struct PolarCoord {
PolarCoord( double a, double v ) : mA(a), mV(v) {}
double mA, mV;
};
Тогда ваши конструкторы станут:
Complex( const CartCoord & c );
Complex( const PolarCoord & c);
При использовании:
Complex c( CartCoord( 1, 2 ) );
Вы также можете использовать их с перегруженными операторами класса Complex. Например, если у вас есть двоичный + оператор для класса, определите как:
Complex operator+( const Complex &, const Complex & );
то
Complex a( CartCoord( 0, 0 ) );
Complex b = a + PolarCoord( 1, 1 );
Поскольку у нас есть конструктор преобразования от PolarCoord to Complex, это будет использоваться в выражении+. Это более естественно (IMHO), чем вызов статических функций для создания временного..
Это пример изложения Кенига (или, по крайней мере, его версии) - всякий раз, столкнувшись с трудной проблемой, вводите новый уровень классов для его решения.
Используйте именованный именованный конструктор, описанный здесь в FAQ по Parashift С++.
Вы не можете - если сигнатуры метода совпадают, вы набиты.
Конечно, вы всегда можете создать подкласс для каждого типа системы координат, но это далеко не идеально - особенно если вы позже найдете веские основания хотеть подкласс Complex по другим причинам...
Вместо двух конструкторов вам нужно иметь только один, но добавить третий параметр, например:
Complex (double re, double img, enum type) {
if(type == polar) {
..treat as polar coordinates..
} else {
..treat as cartesian coordinates..
}
}
'тип enum' также может иметь тип по умолчанию, поэтому вам не нужно указывать, какие типы координат вы собираетесь использовать каждый раз, по умолчанию это должно быть то, что больше всего используется.
Complex (double re, double img, enum type = polar);
Я не знаю, является ли это хорошей практикой в С++, но я бы назвал эти два метода по-разному, по крайней мере, для точки обслуживания.
Я бы, вероятно, создал больше классов, но тогда я являюсь адептом библиотеки Boost Strong Typedef
.
Для меня нет смысла использовать double
для представления координат, модуля и углов.
Итак, я бы:
class CoordinateX {};
class CoordinateY {};
class Modulus {};
class Angle {};
class Complex
{
public:
Complex(CoordinateX, CoordinateY);
Complex(Modulus, Angle);
};
И там это совершенно ясно, и нет никакой двусмысленности. Также вы добавляете некоторую проверку времени "единиц" во время компиляции в свободном смысле. Очень редко (если когда-либо) имеет смысл добавить X-координату и Y-координату или, что еще хуже, расстояние и угол.
Поскольку никто не упоминал об этом, вы можете использовать теги:
class Complex{
struct CartCoord{};
struct PolarCoord{};
Complex( CartCoord, double re, double img);
Complex( PolarCoord, double a, double v);
};
int main(){
auto c1 = Complex(Complex::CartCoord{}, 5, 6);
auto c2 = Complex(Complex::PolarCoord{}, 5, 6);
}
Для меня более элегантным способом было бы создать класс, представляющий декартовы координаты, а другой - полярные координаты, а затем передать объект соответствующего класса конструкторам.
Таким образом, у вас будет два конструктора, использующих разные параметры.
Я использую этот простой альтернативный способ, практикуя С++, я не знаю, хотите ли вы этого.
class Vector{
public:
float x, y;
Vector();
Vector(float , float, bool);
float get_distance(Vector v); // find distance from another vector
float get_magnitude(); // find distance from origin point
Vector add(Vector v);
Vector subtract(Vector v);
Vector multiply(Vector v); // multiply by vector
Vector multiply(float scalar); // multiply by scalar
float get_angle();
};
Vector::Vector(float a, float b, bool is_cartesian = true){
if(is_cartesian){
x = a;
y = b;
}
else{
x = a * cos( b );
y = a * sin( b );
}
}