Перегрузка операций. Введение в тему

Перегрузка операций мне давалась тяжело. Проблема с объяснениями, как мне кажется, налицо. Все друг у друга списывают и никто разъяснить понятно не может. Я тут рискнуть решил, попробовать истолковать понятнее кого бы то ни было. Если удастся, то это будет здорово.
  • Перегрузка — это дополнительные варианты обработки, пригружаемые довеском на одну и ту же сущность (перегрузка функций, перегрузка операций)
В С++ перегружать операции для встроенных типов нельзя, можно только для наших собственных типов (т. е. перегрузка возможна при наличии классов/структур/объединений). Есть два подхода к перегрузке: перегружать операцию внутри класса и перегружать операцию вне класса. Эти подходы незначительно различаются в написании кода.
Первое, что мы сейчас перегрузим — операция + — перегрузим эту операцию для структуры.

Операция сложения — это операция бинарная. Нужно два слагаемых. Поэтому когда мы учим структуру вне класса, нужно передавать два аргумента. Сама перегрузка почти что самая обычная функция, в принципе, она и есть самая обычная функция, но отличает её наличие ключевого оператора operator и обозначение операции, в нашем случае значка сложения. На месте значка сложения могла бы быть любая другая бинарная операция: вычитание, умножение, деление…
Из-за того, что на один символ возложено много разного рода функциональности (функциональность зависит от типа или типов, которые в деле), называют перегрузку перегрузкой. Живёт себе символ спокойно, умеет что-то делать с данными, а тут прилетают новые умения, и постоянно довесок уменями происходит. Грузится символ, грузится, грузится, грузится… Вот поэтому перегрузка.
Объекты сложных типов в функции правильно передавать по ссылке, а те, которые не меняются внутри функций, по константной ссылке, поэтому гораздо приятнее наш код будет выглядет вот в таком виде:


Вы постоянно будете натыкаться на примеры с константными ссылками и просто ссылками, просто потому что именно с ними правильно. Поэтому я привёл в пример #1.3
Перед тем, как идти дальше, вы должны освоить хотя бы пример #1.1. Он очень простой, но без понимания его дальше двигаться будет сложно.
Сложность может возникнуть с возвращаемым значением и типами, указываемыми для параметров. Типы в скобках — это типы уходящих в функцию аргументов. Возвращаемое значение должно совпадать с типом конечной для операции сущности. В показанном примере все типы были представлены одним классом, позднее будет показано для трёх классов.
На возвращаемом значении предлагаю пока что не останавливаться надолго, а изучать тему дальше. Синтаксис для перегрузки операции вне класса и внутри класса отличается. Как по мне, так одной из проблем сложного восприятия темы является порядок выдачи примеров: сначала дают пример с перегрузкой внутри класса, потом или вообще ничего не дают, или всё-таки дают нехотя пример с перегрузкой операции вне класса. По листингам #1. должно быть понятно: бинарная операция, два параметра для перегрузки. С случае с перегрузкой операции внутри класса, один из двух параметров явно передавать не нужно, не нужно передавать тот параметр, о котором известно классу.

При перегрузке бинарной операции в классе, в параметрах должен остаться только один. Вот этот момент меня дико тормозил. Первый параметр представляет из себя уже известный классу объект: это тот объект, к которому будет применена перегружаемая операция, поэтому в параметрах его задавать — излишек. А вот второй параметр классу узнать не от куда, поэтому классу в перегрузке операции нужно подсказать, что то будет за параметр. Фактически у нас при A+B к A применяется плюс, а поскольку плюс применяется к А, то это А будет известно внутри класса, т. е. и перегрузка затачивается под это А, а вот B надо подсказывать. Кто первый слева — тот известен, а следующий — неизвестен. Неизвестный делаем известным с помощью передачи значения в параметр.
Сейчас будет показан, возможно, сложный пример для новичка. Но буду надеяться, что все этот пример понять смогут. Ключ к пониманию — понимание типов, даваемых под возвращаемые значения функций. Суть: если у нас три независимых класса с порождёнными от них объектами и два объекта нужно сложить между собой и вывести результат в третий объект, то делается это вот так (пример вне класса):

В листинге #3.1 нам не пришлось перегружать операцию = только по той причине, что мы свели сложение типов Man + Feman к результату типа Result_Salary. Сведение это получилось благодаря возвращаемому из функции, перегружающей плюс, применяемый к типам Man и Feman. Поскольку мы свели сложение к типу Result_Salary и присваиваем само сложение в объект типа Result_Salary, дополнительных перегрузок (перегрузки операции =) нам не понадобилось. Объекты одного и того же класса можно присваивать друг в друга напрямую. Но ситуация вполне может сложиться и так, что операцию присваивания перегрузить придётся. Операция присваивания бинарная, перегружается так же как плюс, только надо правильно научать классы поведению по применении к ним операции.
Перегрузкой можно давать любой смысл операции. Из значка минуса можно сделать операцию умножения, из операции сложения операцию деления. Устроить можно кавардак. Если вы проникнитесь, то возможно появление адски-сильного желания перегружать что попало как попало, перегружать всё и везде. Но постарайтесь не усложнять код нелогичными вариантами. Перегрузка операций прежде всего нужна для того, чтобы код упрощать. Если перегрузка код усложняет, то это плохо.
В этой теме не рассмотрена перегрузка унарных операций, потому что там есть некоторые особенности, подробное описание из-за чего может затянуться, лучше опишу отдельной статьёй.
    По теме:

  • Перегрузка операций обозначает, что почти любой из известных компилятору операций можно назначить свое поведение.
  • Перегрузка операций требует минимум одного параметра пользовательского типа (структура, класс…). Это предотвращает перегрузку операций, работающих со стандартными типами.
  • Нельзя задавать свои операции.
  • Нельзя перегружать операции способом, ведущим к нарушению синтаксиса исходной операции:

  • Не допускается изменение приоритетов операций.
  • Не допускается перегрузка некоторых встроенных операций.

===========================================

НЕПЕРЕГРУЖАЕМЫЕ ОПЕРАЦИИ
ОПЕРАЦИЯ
ОПИСАНИЕ
КОММЕНТАРИЙ

sizeof
Операция sizeof
Получить размер в байтах

.
Операция членства
Запрос к объекту

.*
Операция указателя на элемент класса


?:
Условная операция
Тернарная операция

typeid
Операция RTTI (runtime type identification — определение типа во время выполнения)
_

const_cast
Операция приведения типа

dynamic_cast
Операция приведения типа

reinterpret_cast
Операция приведения типа

static_cast
Операция приведения типа

  • На некоторые операции накладывается ограничение: перегрузка только внутри класса.
ОПЕРАЦИИ, КОТОРЫЕ НЕЛЬЗЯ ПЕРЕГРУЗИТЬ ВНЕ КЛАССА
ОПЕРАЦИЯ ОПИСАНИЕ
= Операция присваивания
() Операция вызова функции
[] Операция индексации
-> Операция доступа к членам класса через указатель
Использованные материалы:

Язык программирования C++. Лекции и упражнения. 6-е изд (Стивен Прата)

Статья полностью переписана 10.04.2018
Все комментарии на сайте проверяются, поэтому ваш комментарий может появиться не сразу. Для вставки кода в комментарий используйте теги: [php]ВАШ_КОД[/php]

7 комментариев: Перегрузка операций. Введение в тему

  • Vlad говорит:

    «(20-7)/(30.5-10)»- из этого уравнения у меня получилось(0,634146). А На экране 266,5-это что?

  • Алексей говорит:

    У меня получился вот такой код и выводит 0,634146. Откуда вы вообще взяли 266.5?

    Автор сайта отвечает:

    20	30,5	7	10
    ___________
    20-7  =	 13
    30,5-10= 20,5
    ___________
       13*20,5=   266,5
    
  • дон говорит:

    thanks ^^!

  • kirill говорит:

    Почему мы 13 и 20.5 умножае ?если по вашей формуле нужно делить.Вы показываете умножение,а перегрузка оператора не нужна?

  • kirill говорит:

    Вы мне подскажите,может я что-то неправильно понимаю.

    • admin говорит:

      Перегрузка операторов — это изменение смысла оператора. Плюсом можно не только складывать, но и делить и умножать и даже описывать решение сложных формул. Чтобы плюс делал нечто подобное, его поведение описывают в том же виде, как описывают функции.
      Это не самый удачный пример получился, к сожалению, смысл этой задачки только в том, чтобы понять что поведение операторов можно описать удобным для нас способом.

  • kirill говорит:

    Спасибо за ответ.

Добавить комментарий

Ваш e-mail не будет опубликован.

− 3 = 1

Поиск

 
     

Случайная книга в электронном формате

https://www.litres.ru/denis-kolisnichenko/programmirovanie-dlya-android-samouchitel/?lfrom=15589587
Яндекс.Метрика
НАГРАДИ АВТОРА САЙТА
WEBMONEY
R375024497470
U251140483387
Z301246203264
E149319127674

Отец перед сном рассказывает сыну сказку: - Жил на свете богатый человек. Купил он себе самый лучший компьютер и кучу лицензионных программ. - Пап, а как это - лицензионных? - Спи, сынок, я же сказал - это сказка! . .

Выражаю свою признательность

  • Максиму очень признателен за указание на мои ошибки и неточности.
  • Sergio ===> за оказание помощи в исправлении моих ошибок
  • Gen ===> за правильное стремление помочь другим новичкам и выявления моих ошибок