2012-08-21 3 views
2

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

const fraction fraction::operator* (fraction frac) 
{ 
    return fraction(frac.numerator * numerator, frac.denominator * denominator); 
} 

const fraction fraction::operator* (int num) 
{ 
    return fraction(numerator*num, denominator); 
} 

fraction& fraction::operator= (const fraction &rightSide) 
{ 
    return *this; 
} 

Эти операции являются те, которые я нашел, чтобы работать правильно (где гидроразрыва # представляет собой часть объекта):

frac1 = frac2; 
frac3 = frac4 * 2; 
frac5 = frac6 * frac7; 

Вышеуказанные операции работают, как и ожидалось, но следующая операция оставляет frac8 так же, как он был инициализирован:

fraction frac8(4, 5); // Initializes a fraction, setting numerator = 4, denominator = 5 
frac8 = frac8 * 3; // This doesn't quite work, leaving frac8 with the original numerator/denominator 

Я просто не понимаю, почему вполне frac3 = frac4 * 2 работает, но frac8 = frac8 * 3 нет. Есть идеи? Использование ключевого слова const в операторе присваивания я нашел не решением.

+0

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

ответ

4

Как вы ожидаете, что ваш operator= сделает что-нибудь полезное, если в его теле вы только что делаете return *this;? Вы должны присвоить полям this полям rightSide.

Но, что еще более важно, если ваш класс не управляет ресурсами, которые нуждаются в каком-либо конкретном обращении в случае копирования, вы можете просто уйти с оператором присваивания компилятором. Он просто копирует поля одного экземпляра в другой, что для класса fraction выглядит отлично.

Кстати, обычно вы применяете «обычные» операторы, используя их составные копии; вы можете взглянуть на operator overloading FAQ.

+0

Спасибо за ссылку. Я не совсем понял, что копия по умолчанию будет работать в этом случае. Это в основном для обучения/практики. – SteveC

0

Ваш оператор присваивания возвращает только сам объект (т. Е. *this) ... поэтому в последнем примере это просто операция no-op, а не выполнение фактической операции присваивания из правого объекта. Другими словами, временный объект fraction создается вашим operator*, но поскольку ваш оператор присваивания не копирует значения объекта правой стороны, вы просто просто отбрасываете временный экземпляр fraction, сгенерированный operator* после завершения метода operator=.

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

+0

Я должен быть смущен относительно того, что это делает. Я думал, что это правый объект. Почему это 'frac3 = frac4 * 2;' работает. Казалось бы, это утверждение действительно должно оцениваться как «frac3 = frac4», учитывая то, что вы сказали. Спасибо за ссылку «правило три». Хотя этот класс не имеет ничего динамически распределенного, я все еще просто пытаюсь научиться/практиковать. – SteveC

+0

Откуда вы знаете, что это «работает»? Какова была начальная величина 'frac4', и каковы были результаты' frac3' после того, как выражение было завершено? В вашем примере кода кажется, что только «frac8» проверяется до/после, чтобы заметить, что объект не меняется. – Jason

+0

'фракция frac8 (6, 20);' 'фракция frac9 = frac8 * 2;' 'std :: cout <<" \ nfrac8 = "<< frac8.toStringS() << std :: endl;' 'std :: cout <<" frac9 = frac8 * 2 \ n "<<" frac9 = "<< frac9.toStringS() << std :: endl;' Я часть моего скомпилированного и протестированного кода. Вывод на консоль: 'frac8 = 6/20 frac9 = frac8 * 2 frac9 = 12/20' Указанный код был сильно урезан, что означало только то, с чем я столкнулся. – SteveC

1

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

I.e. ни одно из этих трех назначений

frac1 = frac2; 
frac3 = frac4 * 2; 
frac5 = frac6 * frac7; 

действительно работает.

Почему-то вы утверждаете, что вышеупомянутые задания «работают», но это должно быть чем-то вроде путаницы с вашей стороны. Они не «работают». Также нет frac8 = frac8 * 3, по той же причине.

P.S. Я подозреваю, что ваши «рабочие» заявления были в действительности написан таким образом

fraction frac1 = frac2; 
fraction frac3 = frac4 * 2; 
fraction frac5 = frac6 * frac7; 

Это действительно может работать. Но этот синтаксис не имеет ничего общего с оператором присваивания. Оператор присваивания в таких случаях не используется. Этот синтаксис соответствует копировальной инициализации. Он полагается на экземпляр-конструктор класса (по крайней мере концептуально), а не на оператор присваивания. Вот почему это может сработать, в то время как истинное назначение не работает, потому что вы «вывели из строя» оператор копирования-присваивания, сделав его пустым.

+0

Я полагал, что они работали после проверки, вызывая функции toString() и выводя их на консоль. Например; Я инициализировал фракцию, скажем, frac1, а затем установил frac2 равным frac1. frac2 принимает атрибуты frac1 и остается тем, что должно быть, даже если frac1 будет изменен любым способом. Так сказать, что это не «работает», это озадачивает. В приведенных примерах он работал по назначению. – SteveC

+0

@ user1450120: Это означало бы, что значения, которые вы * ожидали * увидеть в объектах левой стороны, каким-то образом попали туда случайно, без какой-либо помощи от вашего оператора присваивания. Это [неверное] побудило вас поверить, что ваш оператор назначения как-то работал, а на самом деле это не так. – AnT

+0

Интересно, я не думал, что 'fraction frac3 = frac4 * 2;' будет отличаться от 'frac3 = frac4 * 2;' Спасибо за информацию. Я действительно подтвердил, что инициализация frac3 перед использованием оператора присваивания оставила меня с нежелательными эффектами. Благодарю. – SteveC

Смежные вопросы