перегрузка операторов и функции, не являющиеся членами С++

Я написал класс для комплексных чисел, в котором я перегрузил оператор +, и все работает нормально, однако мне нужно реализовать это как функцию, не являющуюся членом, и я не уверен, как и почему это выгодно.

Вот мой код .h:

class Complex
{
private:
    double a;
    double b;

public:
    Complex();
    Complex(double aGiven);
    Complex(double aGiven, double bGiven);

    double aGetValue();
    double bGetValue();    
    double operator[](bool getB);

    Complex add(Complex &secondRational);
    Complex operator+(Complex &secondRational);
}

.cpp:

Complex Complex::add(Complex &secondRational)
{
    double c = secondRational.aGetValue();
    double d = secondRational.bGetValue();
    double anew = a+c;
    double bnew = b+d;
    return Complex(anew,bnew);
}

Complex Complex::operator+(Complex &secondRational)
{
    return add(secondRational);
}

Мы будем очень признательны за любую помощь в том, как сделать их функциями, не являющимися членами!


person user906357    schedule 09.10.2013    source источник
comment
возможный дубликат перегрузки оператора   -  person Xeo    schedule 10.10.2013
comment
Вам нужно прочитать о const. Очень срочно.   -  person sbi    schedule 10.10.2013


Ответы (4)


Вот оператор сложения вне класса:

Complex operator+(const Complex& lhs, const Complex& rhs) {
  //implement the math to add the two
  return Complex(lhs.aGetValue() + rhs.aGetValue(),
                 lhs.bGetValue() + rhs.bGetValue());
}

Конечно, вам нужно будет объявить aGetValue() и bGetValue() как const:

double aGetValue() const {return a;}
double bGetValue() const {return b;}
person pippin1289    schedule 09.10.2013

Вы можете объявить друга в свой Complex класс

class Complex {

// blah....

    friend Complex operator+(Complex const& a, Complex const & b);
};

Перегруженный оператор может получить доступ к закрытым членам Complex.

person CS Pei    schedule 09.10.2013

Обычный подход к арифметическим операциям состоит в том, чтобы определить рефлексивные версии операторов как члены, а чистые версии как нечлены, реализуя их с рефлексивными версиями:

class complex {
public:
    const complex& operator+=(const complex& rhs) {
        real += rhs.real;
        imag += rhs.imag;
        return *this;
    }
};

complex operator+(const complex& lhs, const complex& rhs) {
    complex res(lhs);
    res += rhs;
    return res;
}
person Pete Becker    schedule 09.10.2013
comment
@DanielFrey - я почти сделал это, но решил, что это слишком запутанно. - person Pete Becker; 10.10.2013
comment
Теперь вам удалось запутать меня. Почему вы думаете, что это будет запутанно? Учитывая, что int i = 0; (i+=1)+=2; допустимо для целочисленных типов, почему оно не должно быть допустимо для UDT? - person Daniel Frey; 10.10.2013
comment
@DanielFrey - (i+=1)+=2; сбивает с толку. <g> i += 1 + 2; намного лучше. - person Pete Becker; 10.10.2013
comment
ОК, с этим не поспоришь :) (не то чтобы я принял этот стиль, но соглашусь, что в этом случае возможны и другие мнения. Также: i+=j+k не лучше для UDT, так как он создаст временный и, следовательно, он менее эффективен). - person Daniel Frey; 10.10.2013
comment
@DanielFrey: вы говорите, что выражения i + j + k теперь труднее оптимизировать, чем если бы += возвращалось по неконстантной ссылке? Кроме того, я думаю, что делать то, что делают целые числа, важно в универсальном коде и должно преобладать над запретом пользователям писать непонятный код. - person TemplateRex; 10.10.2013
comment
@DanielFrey - меня не беспокоит лишний объект типа complex. - person Pete Becker; 10.10.2013
comment
Извините, но я должен понизить его, потому что это удивительно для любого, кто пишет тонкую оболочку вокруг встроенной функции, которая использует цепное присваивание (хотя я согласен, что это неясный код). Если вы хотите продвигать неканоническую версию со ссылкой на константу, я думаю, это следует сделать в виде комментария или ответа на канонический вопрос. - person TemplateRex; 10.10.2013
comment
@TemplateRex Временные объекты не имеют большого значения, если объекты маленькие, Complex здесь всего два двойника. Но раньше я работал с Complex<T>, а T был высокоточным пользовательским типом с основанием 10. Или подумайте о матрицах. Именно здесь становится важно избегать временных и почему такие библиотеки, как мой df.operators, стараются избегать их. И именно поэтому вы, ИМХО, должны позволять пользователям писать такие глупости, как (i+=j)+=k;. Да, здравомыслящий человек использовал бы i+=j; i+=k;, но мой опыт говорит, что я не могу все время предполагать нормальное поведение других :-) - person Daniel Frey; 10.10.2013
comment
@DanielFrey Я думаю о больших std::bitset объектах со сложными логическими выражениями. - person TemplateRex; 10.10.2013
comment
@TemplateRex Еще один хороший пример, когда i&=j; i|=k; может быть менее эффективным, поскольку оптимизатор может не иметь возможности просматривать память только один раз по сравнению с (i&=j)|=k. Очевидно, это все настроение без измерения. Учитывая ваш отрицательный голос: вы можете сбалансировать его с ответом Пита, который является единственным, который продвигает +, реализуемый с +=. - person Daniel Frey; 10.10.2013
comment
@DanielFrey согласился с +=, но, поскольку это похоже на четырехкратный обман +500 вопросов и ответов, я думаю, что он вообще не должен был получить никакого ответа. - person TemplateRex; 10.10.2013
comment
@TemplateRex - значит, вы отрицаете мой ответ, потому что считаете, что вопрос должен был быть закрыт как дубликат? Это бессмысленно. - person Pete Becker; 10.10.2013
comment
@PeteBecker нет, обман был побочным замечанием. Я проголосовал за ссылку const, потому что она отличается от встроенного поведения и стандартной практики libray и, вполне возможно, из-за пессимизации производительности. - person TemplateRex; 10.10.2013
comment
@TemplateRex - за деревьями не видно леса. - person Pete Becker; 10.10.2013
comment
@PeteBecker извините, как такие комментарии помогут мне увидеть то, что вы считаете таким очевидным? Я привел 2 имхо законных причины для понижения голосов, и вы не ответили ни на одну из них. - person TemplateRex; 10.10.2013
comment
T x; T& y = (x += 1); должно быть действительным. Не потому, что я хочу его использовать, а потому, что у вас нет веских причин запрещать мне это делать. Конец истории! - person Lightness Races in Orbit; 10.10.2013
comment
Do as ints do — это очень простое правило перегрузки операторов, и я согласен с этим. Этот класс operator+=() нарушает это правило. - person sbi; 10.10.2013
comment
(+1 все еще хороший ответ, исправьте в противном случае и, кстати, безусловно, лучший) - person Lightness Races in Orbit; 10.10.2013

Как объяснил выше pippin1289.

Почему объясняется ниже:

Представьте, что вам нужно использовать объект класса как

Complex c3 = 5 + c1;// for c3 object c1's real part (a) added with 5

Поскольку С++ сохраняет порядок операндов. Компилятор разрешает вышеуказанный вызов добавления как 5.operator+ (const Complex & other);// что невозможно Следовательно, перегрузите его через свободную функцию.

Ваш класс предоставляет необходимую информацию через общедоступный интерфейс, такой как aGetValue() и bGetValue. Следовательно, эта свободная перегруженная операторная функция + не обязательно должна быть дружественной по классу.

Кроме того, предпочтите недружественную функцию-член вместо функции-члена, поскольку это помогает снизить степень инкапсуляции. Это объясняется здесь ==> http://www.drdobbs.com/cpp/how-non-member-functions-improve-encapsu/184401197?pgno=1

person sidd.rane    schedule 03.10.2015