Можно ли каскадировать перегруженный оператор извлечения с перегруженными арифметическими операторами?

Я пытаюсь реализовать класс COMPLEX в С++ и перегружать арифметические операторы, а также операторы «‹‹» и «>>» для ввода/вывода. По отдельности, а также при каскадировании арифметические операторы работают должным образом, но я не могу получить правильные результаты при попытке выполнить такие операторы, как:

cout &lt&lt "something" &lt&lt complex1 + complex2 &lt&lt "\n";

где комплекс1 и комплекс2 — объекты класса КОМПЛЕКС.

фрагменты определения класса:

class COMPLEX{
    int a;  // Real part
    int b;  // Imaginary part
public:
    COMPLEX operator = (COMPLEX );
    COMPLEX operator + (COMPLEX ) const;
    friend istream& operator &gt&gt (istream &, COMPLEX &);
    friend ostream& operator &lt&lt (ostream &, COMPLEX &);
-snip-
}


COMPLEX COMPLEX::operator = (COMPLEX t_c) {
    return COMPLEX(a = t_c.a, b = t_c.b);
}

COMPLEX COMPLEX::operator + (COMPLEX t_c) const{
    return COMPLEX(a + t_c.a, b + t_c.b);
}

istream& operator &gt&gt (istream &i_s, COMPLEX &t_c){
    i_s &gt&gt t_c.a &gt&gt t_c.b;
    return i_s;
}

ostream& operator &lt&lt (ostream &o_s, COMPLEX &t_c){
    o_s &lt&lt t_c.a &lt&lt "+" &lt&lt t_c.b &lt&lt "i";
    return o_s;
}

помимо этого у меня также есть перегруженный оператор.

Всякий раз, когда я пытаюсь каскадировать ‹‹ с любым другим перегруженным оператором, перегруженная функция ‹‹ не вызывается. Вместо этого вызывается оператор, и результат этого отображается.


person kny8mare    schedule 05.02.2011    source источник


Ответы (4)


Проблема в том, что ваш оператор вставки потока определяется как

friend ostream& operator << (ostream &, COMPLEX &);

Это принимает неконстантную ссылку на объект COMPLEX в качестве второго параметра. Когда вы пытаетесь написать

cout << a + b << endl;

Значением a + b является rvalue, а не lvalue, поскольку это значение, возвращаемое функцией operator +. В C++ вы не можете привязать ссылку к rvalue, так как тогда вы можете делать Плохие вещи следующим образом:

COMPLEX& c = a + b; // This step isn't legal
c = 137;            // Wait, what object did we just change?

Проблема здесь в том, что если мы можем связать ссылку c с временным объектом, возвращаемым a + b, то мы можем использовать ссылку для внесения изменений в этот объект. Но это не имеет никакого смысла — a + b — это значение выражения, а не реальный объект.

Это та же проблема, что и здесь. Ваша функция operator << не может принимать a + b в качестве второго параметра, поскольку a + b является rvalue.

Чтобы исправить это, вы можете изменить operator <<, чтобы взять const ссылку на КОМПЛЕКС:

friend ostream& operator<< (ostream& out, const COMPLEX& c);

Это работает, потому что в C++ вы можете привязать константные ссылки к rvalue. Обоснование этого заключается в том, что если у вас есть константная ссылка на временный объект, вы не можете вносить какие-либо изменения в этот временный объект, поэтому приведенный выше пример с привязкой ссылки к a + b больше не является проблемой.

В общем, любой перегруженный оператор, который принимает параметр, тип которого является другим экземпляром класса, который не изменяет этот экземпляр, должен принимать свой параметр по константной ссылке. Это касается таких вещей, как operator =, operator + и т. д., поскольку позволяет избежать этой проблемы.

person templatetypedef    schedule 05.02.2011
comment
Большое спасибо :) Как раз то объяснение, которое я искал - person kny8mare; 06.02.2011

Ваш оператор ‹‹ должен принимать постоянную ссылку, иначе компилятор не сможет преобразовать временный тип COMPLEX (полученный в результате добавления) в неконстантную ссылку и может искать альтернативный оператор ‹‹ для вызов.

friend ostream& operator << (ostream &, const COMPLEX &); //notice "const"

Чтобы понять остальную часть механики операторов, достаточно взглянуть на таблицу приоритетов операторов.

person Mikael Persson    schedule 05.02.2011

перепишите свой оператор cout на

cout << "something" << (complex1 + complex2) << "\n";
person KitsuneYMG    schedule 05.02.2011
comment
Да! Я пробовал это раньше, и это работает. Но мне было интересно, можем ли мы выполнять такие операции, как cout ‹‹ 1 + 2; тогда должно ли это относиться и к вышеизложенному? - person kny8mare; 05.02.2011
comment
Ой! попробовал ваш метод.. все равно не работает. Результат, как и раньше, приводится к типу int. Единственный способ, которым я могу сделать эту работу, - это присвоить результат третьему объекту типа COMPLEX, а затем вычислить его. - person kny8mare; 05.02.2011

Ваша проблема в том, что оператор‹‹ всегда вызывается перед оператором +. Тот факт, что вы предоставляете перегрузки, не меняет этого.

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

person Bo Persson    schedule 06.02.2011