Программирование >>  Аргументация конструирования 

1 ... 83 84 85 [ 86 ] 87 88 89 ... 108



Нет правила, заставляющего функцию operator+(USDollarS, USDollarS;) осуществлять именно сложение. Вы можете заставить функцию operator+ () выполнять любые действия; однако выполнение этим оператором чего-либо, кроме сложения, очень-очень плохая идея. Люди привыкли к тому, что их операторы выполняют определенные действия. Вряд ли им понравится, если привычные операторы начнут выполнять непривычные действия.

Оператор += не имеет понятия, как нужно скомбинировать операторы + и =. Таким образом, каждый оператор должен быть перегружен отдельно.

Если вы определили только один оператор- operator+ + () или operator-(), он будет иснользован как для нрефиксной, так и для постфиксной формы. Правда, стандарт C + + не требует от компилятора такой сообразительности, однако большинство компиляторов C++ умеют это делать.

Изначально в C + + не было возможности переопределять префиксный оператор ++х отдельно от его постфиксной версии х++. Однако многим программистам это не нравилось, поэтому правило изменили. В соответствии С ЭШМ правилом operator + + (className) ОШЭСИГО! К префиксному оператору, a operator + + (ClassName, int) - к постфиксному. В качестве второго аргумента при этом всегда передается 0. То же правило распространяется и на оператор декремента -- .

В работе такие операторы оказываются довольно удобными. Что может быть проще, чем строка d3 dl + d2 или ++d3?



щ4 HaqftoHee?

Почему аtort () возвращает сумму по значению, a operator + + () возвращает увеличенный на единицу объект по ссылке? Это не случайность, здесь кроется очень большое отличие между этими операторами!

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


operator+()

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

Очень неудачная мгсль выполнять сложение так, как это сделано в данной программе, поскольку будет изменяться значение одного из аргументов USDollari operator+(USDollarS si, USDollarS s2)

si.cents += s2 -cents; if (si.cents >=100)

si.cents -= 100 ; s1.dollars++;

si.dollars += s2.dollars;




return sl;

Проблема в том, что в результате такого простого присвоения, ка ul = u2 т u3;, будут изменены значения и ul и и2.

Чтобы избежать этого, operator+() должен создавать временный объект, в котором и будет сохранен результат сложения. Поэтому operator+ () конструирует собственный объект, который возвращается этой функцией.

Однако при этом нельзя забывать и еще кое-что! Например, приведенный ниже

фрагмент работать не будет.

USDollars opeiator+(USDollars si, USDollarS s2)

unsigned int cents - si.cents + s2.cents; unsigned int dollars = si.dollars т s2.dollars; USDollar result(dollars, cents);

return result

Распространенная ошибка № 1. Хотя этот фрагмент откомпилируется без со

общений об ошибке, результат выполнения этой функции будет весьма плачевным. Проблема в том, что возвращается ссылка на объект result, который является локальным для данной функции. Таким образом, к тому времени, как вызывающая функция сможет использовать возвращаемый

результат, объект result уже выйдет из области видимости.

Тогда почему бы нам не выделить блок памяти из кучи так, как это сделано в приведенном ниже примере?

USDollars operatort (USDollars si, USDollarS s2) f

unsigned int cents = si.cents + s2.cents; unsigned int dollars = si. dollars т s2. dollars; return *new USDollar(dollars, cents);

Распространенная ошибка № 2, Вы, конечно, можете вернуть ссылку на объект, память под который была выделена из кучи, однако возникнет новая проблема: при этом не предусматривается механизм возврата памяти в кучу. Эта ошибка называется утечкой памяти, и ее очень сложно отыскать. Хотя

такой оператор и будет работать, он будет потихоньку истощать память

в куче при каждом выполнении сложения.

Возврат по значению заставляет компилятор создавать временный объект в стеке вызывающей функции. Затем созданный функцией объект копируется в этот временный объект.

Возникает вопрос: как долго существует временный объект, который возвращает operator+ () ? Изначально это не было определено, однако затем создатели стандартов собрались вместе и решили, что такой временный объект остается необходимым до завершения развернутого выражения. Развернутое выражение - это все, что находится перед точкой с запятой. Рассмотрим, например, такой фрагмент:

SomeClass f ( ) ; LotsClass g 0 ; fn()..





mt i;

i = f!) U-g{));

Временный объект, возвращенный функцией f (), существует, пока выполняется функция д() и пока выполняется умножение. Тамде стоит точка с запятой, этот объект уже недоступен.

operator+ + ()

В отличие ator+ (), функции loe++ (} модифицирует свой аргумент. А значит, вам не нужно создавать временный объект иди возвращать результат но

значению. Вычисляемый результат можно хранить прямо в s. Вызывающей функции

может быть возвращен предоставленный оператору аргумент.

это будет отлично работать USDollarS operator++(USDollarb s)

s.cen ts + +;

nts 100)

£.cents -=10 0; £.dollars++;

return s;

приведенный ниже пример, который содержит одну очень хитрую

ошибку.

это не очен ;{сная версия USDollar operatorT+(uSDollaru s)

s.cents** ;

if (£;. cents >= 100)

s . cents - = 100; s.dollars++;

return s;

Распросграненная ошибка № 3. Возвращая значению, функция застав-

ляет компилятор генерировать копию объекта. Это отлично сработает в выражениях тина а = 4+Ь, но что будет с выражениями тина ++(++а)? Мы ожидаем, что а будет увеличено на 2. Однако при приведенном выше переопределении этого оператора, объект а будет увеличен на 1, а затем на 1 будет увеличена его копия, а не сам объект а.

Конструкция вида +* (*+а) не очень распространена, но все же допустима. В любом случае имеется еще множество примеров, в которых такой оператор не будет работать правильно.

Можно сформулировать следующее правило: если оператор изменяет значение своего аргумента, возвращайте аргумент по ссылке. Если оператор не изменяет значения своих аргументов, создавайте новый объект и возвращайте его по значению. Входные аргументы лучше всегда передавать по ссылке.





1 ... 83 84 85 [ 86 ] 87 88 89 ... 108

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика