Как различить два конструктора с одинаковыми параметрами? - PullRequest
32 голосов
/ 15 марта 2010

Предположим, нам нужны два конструктора для класса, представляющего комплексные числа:

Complex (double re, double img)  // construct from cartesian coordinates
Complex (double A, double w) // construct from polar coordinates

но параметры (число и тип) одинаковы: какой способ более элегантный определить, что предназначено? Добавление третьего параметра в один из конструкторов?

Ответы [ 10 ]

43 голосов
/ 15 марта 2010

Лучше добавить статические методы с соответствующими именами и позволить им создавать объекты.

static Complex createFromCartesian(double re, double img);
static Complex createFromPolar(double A, double w);
36 голосов
/ 15 марта 2010

У вас не может быть двух конструкторов (или каких-либо функций) с одинаковыми сигнатурами. Наилучшим решением, вероятно, является создание классов для ваших типов координат и их перегрузка. Например:

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 в Complex, он будет использоваться в выражении +. Это более естественно (IMHO), чем вызов статических функций для создания временных ..

Это пример изречения Кенига (или, по крайней мере, его версии) - всякий раз, когда возникает трудная проблема, вводите новый уровень классов для ее решения.

8 голосов
/ 15 марта 2010

Используйте идиому именованного конструктора, описанную здесь в Parashift C ++ FAQ.

5 голосов
/ 15 марта 2010

Вы не можете - если сигнатуры методов совпадают, вы набиты.

Конечно, вы всегда можете создать подкласс для каждого типа системы координат, но это далеко от идеала - особенно если позже вы найдете вескую причину для того, чтобы захотеть создать подкласс Complex по другим причинам ...

3 голосов
/ 15 марта 2010

Вместо двух конструкторов вам нужно иметь только один, но добавить третий параметр, например:

Complex (double re, double img, enum type) {
  if(type == polar) {
    ..treat as polar coordinates..
  } else {
    ..treat as cartesian coordinates..
  }
}

'enum type' также может иметь тип по умолчанию, так что вам не нужно указывать, какой тип координат вы собираетесь использовать каждый раз, по умолчанию, конечно, должно быть то, что используется чаще всего.

Complex (double re, double img, enum type = polar);
1 голос
/ 16 октября 2017

Поскольку никто не упомянул об этом, вы можете использовать теги:

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);
}
1 голос
/ 15 марта 2010

Возможно, я бы создал больше классов, но тогда я адепт Boost Strong Typedef библиотеки.

Для меня не имеет смысла использовать double для представления координат, модуля и углов.

Итак, я бы получил:

class CoordinateX {};
class CoordinateY {};

class Modulus {};
class Angle {};

class Complex
{
public:
  Complex(CoordinateX, CoordinateY);
  Complex(Modulus, Angle);
};

И там это совершенно ясно, и нет никакой двусмысленности. Также вы добавляете некоторую проверку "модулей" во время компиляции в свободном смысле. Редко имеет смысл (если вообще когда-либо) добавлять координаты X и Y, или, что еще хуже, расстояние и угол.

1 голос
/ 15 марта 2010

Я не знаю, является ли это хорошей практикой в ​​C ++, но я бы назвал эти два метода по-разному, по крайней мере, с точки зрения удобства обслуживания.

0 голосов
/ 05 августа 2016

Я использую этот простой альтернативный способ во время практики C ++, я не знаю, если это то, что вы хотите.

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 );
    }
}
0 голосов
/ 15 марта 2010

Для меня более элегантным способом было бы создать класс, представляющий декартовы координаты, и другой, представляющий полярные координаты, а затем передать объект соответствующего класса конструкторам.

Таким образом, у вас будет два конструктора, использующих разные параметры.

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