Operator c что это
Перейти к содержимому

Operator c что это

Перегрузка операторов в C++

Желание написать данную статью появилось после прочтения поста Перегрузка C++ операторов, потому что в нём не были раскрыты многие важные темы.

Самое главное, что необходимо помнить — перегрузка операторов, это всего лишь более удобный способ вызова функций, поэтому не стоит увлекаться перегрузкой операторов. Использовать её следует только тогда, когда это упростит написание кода. Но, не настолько, чтобы это затрудняло чтение. Ведь, как известно, код читается намного чаще, чем пишется. И не забывайте, что вам никогда не дадут перегрузить операторы в тандеме со встроенными типами, возможность перегрузки есть только для пользовательских типов/классов.

Синтаксис перегрузки

Синтаксис перегрузки операторов очень похож на определение функции с именем operator@, где @ — это идентификатор оператора (например +, -, <<, >>). Рассмотрим простейший пример:

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

В большинстве случаев, операторы (кроме условных) возвращают объект, или ссылку на тип, к которому относятся его аргументы (если типы разные, то вы сами решаете как интерпретировать результат вычисления оператора).

Перегрузка унарных операторов

Рассмотрим примеры перегрузки унарных операторов для определенного выше класса Integer. Заодно определим их в виде дружественных функций и рассмотрим операторы декремента и инкремента:

Теперь вы знаете, как компилятор различает префиксные и постфиксные версии декремента и инкремента. В случае, когда он видит выражение ++i, то вызывается функция operator++(a). Если же он видит i++, то вызывается operator++(a, int). То есть вызывается перегруженная функция operator++, и именно для этого используется фиктивный параметр int в постфиксной версии.

Бинарные операторы

Рассмотрим синтаксис перегрузки бинарных операторов. Перегрузим один оператор, который возвращает l-значение, один условный оператор и один оператор, создающий новое значение (определим их глобально):

Во всех этих примерах операторы перегружаются для одного типа, однако, это необязательно. Можно, к примеру, перегрузить сложение нашего типа Integer и определенного по его подобию Float.

Аргументы и возвращаемые значения
  • Если аргумент не изменяется оператором, в случае, например унарного плюса, его нужно передавать как ссылку на константу. Вообще, это справедливо для почти всех арифметических операторов (сложение, вычитание, умножение. )
  • Тип возвращаемого значения зависит от сути оператора. Если оператор должен возвращать новое значение, то необходимо создавать новый объект (как в случае бинарного плюса). Если вы хотите запретить изменение объекта как l-value, то нужно возвращать его константным.
  • Для операторов присваивания необходимо возвращать ссылку на измененный элемент. Также, если вы хотите использовать оператор присваивания в конструкциях вида (x=y).f(), где функция f() вызывается для для переменной x, после присваивания ей y, то не возвращайте ссылку на константу, возвращайте просто ссылку.
  • Логические операторы должны возвращать в худшем случае int, а в лучшем bool.
Оптимизация возвращаемого значения

При создании новых объектов и возвращении их из функции следует использовать запись как для вышеописанного примера оператора бинарного плюса.

Честно говоря, не знаю, какая ситуация актуальна для C++11, все рассуждения далее справедливы для C++98.
На первый взгляд, это похоже на синтаксис создания временного объекта, то есть как будто бы нет разницы между кодом выше и этим:

Но на самом деле, в этом случае произойдет вызов конструктора в первой строке, далее вызов конструктора копирования, который скопирует объект, а далее, при раскрутке стека вызовется деструктор. При использовании первой записи компилятор изначально создаёт объект в памяти, в которую нужно его скопировать, таким образом экономится вызов конструктора копирования и деструктора.

Особые операторы

В C++ есть операторы, обладающие специфическим синтаксисом и способом перегрузки. Например оператор индексирования []. Он всегда определяется как член класса и, так как подразумевается поведение индексируемого объекта как массива, то ему следует возвращать ссылку.

Оператор запятая

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

Оператор разыменования указателя

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

Оператор присваивания

Как можно заметить, в начале функции производится проверка на самоприсваивание. Вообще, в данном случае самоприсваивание безвредно, но ситуация не всегда такая простая. Например, если объект большой, можно потратить много времени на ненужное копирование, или при работе с указателями.

Неперегружаемые операторы

Некоторые операторы в C++ не перегружаются в принципе. По всей видимости, это сделано из соображений безопасности.

  • Оператор выбора члена класса «.».
  • Оператор разыменования указателя на член класса «.*»
  • В С++ отсутствует оператор возведения в степень (как в Fortran) «**».
  • Запрещено определять свои операторы (возможны проблемы с определением приоритетов).
  • Нельзя изменять приоритеты операторов
Рекомендации к форме определения операторов

Как мы уже выяснили, существует два способа операторов — в виде функции класса и в виде дружественной глобальной функции.
Роб Мюррей, в своей книге C++ Strategies and Tactics определил следующие рекомендации по выбору формы оператора:

Оператор Рекомендуемая форма
Все унарные операторы Член класса
= () [] -> ->* Обязательно член класса
+= -= /= *= ^= &= |= %= >>= <<= Член класса
Остальные бинарные операторы Не член класса

Почему так? Во-первых, на некоторые операторы изначально наложено ограничение. Вообще, если семантически нет разницы как определять оператор, то лучше его оформить в виде функции класса, чтобы подчеркнуть связь, плюс помимо этого функция будет подставляемой (inline). К тому же, иногда может возникнуть потребность в том, чтобы представить левосторонний операнд объектом другого класса. Наверное, самый яркий пример — переопределение << и >> для потоков ввода/вывода.

Перегрузка операторов

Ключевое operator слово объявляет функцию, указывающую, что означает оператор-символ при применении к экземплярам класса. Это дает оператору более одного значения — «перегружает» его. Компилятор различает разные значения оператора, проверяя типы его операндов.

Синтаксис

Тип operator operator-symbol(parameter-list)

Комментарии

Функцию большинства встроенных операторов можно переопределить глобально или для отдельных классов. Перегруженные операторы реализуются в виде функции.

Имя перегруженного оператора — operator x, где x является оператором, как показано в следующей таблице. Например, чтобы перегрузить оператор сложения, необходимо определить функцию с именем operator+. Аналогичным образом, чтобы перегрузить оператор сложения или присваивания, +=определите функцию, называемую оператором+=.

Переопределяемые операторы

1 Две версии унарных операторов приращения и уменьшения существуют: preincrement и postincrement.

Дополнительные сведения см. в общих правилах перегрузки операторов . Ограничения для разных категорий перегруженных операторов описываются в следующих разделах.

C++ — Операторы

Оператор — это символ, который сообщает компилятору выполнить определенные математические или логические манипуляции. C ++ богат встроенными операторами и предоставляет следующие типы операторов:

  • Арифметические операторы
  • Реляционные операторы
  • Логические операторы
  • Побитовые операторы
  • Операторы присваивания
  • Другие операторы

Арифметические операторы

Существуют следующие арифметические операторы, поддерживаемые языком C ++:

Оператор Описание Пример
+ Добавляет два операнда A + B даст 30
Вычитает второй операнд с первого A — B даст -10
* Умножает оба операнда A * B даст 200
/ Делит числитель на де-числитель B / A даст 2
% Оператор модуля и остаток после целочисленного деления B% A даст 0
++ Оператор приращения увеличивает целочисленное значение на единицу A ++ даст 11
Уменьшает целочисленное значение на единицу A— даст 9

Реляционные операторы

Существуют следующие реляционные операторы, поддерживаемые языком C ++:

Оператор Описание Пример
== Проверяет, равны ли значения двух операндов или нет, если да, то условие становится истинным. (A == B) не соответствует действительности.
знак равно Проверяет, равны ли значения двух операндов или нет, если значения не равны, условие становится истинным. (A! = B) истинно.
> Проверяет, превышает ли значение левого операнда значение правого операнда, если да, тогда условие становится истинным. (A> B) неверно.
< Проверяет, является ли значение левого операнда меньше значения правильного операнда, если да, тогда условие становится истинным. (A <B) истинно.
> = Проверяет, превышает ли значение левого операнда значение правого операнда, если да, тогда условие становится истинным. (A> = B) неверно.
<= Проверяет, является ли значение левого операнда меньше или равно значению правильного операнда, если да, тогда условие становится истинным. (A <= B) истинно.

Логические операторы

Существуют следующие логические операторы, поддерживаемые языком C ++:

Оператор Описание Пример
&& Вызывается логическим оператором AND. Если оба операнда отличны от нуля, условие становится истинным. (A && B) является ложным.
|| Вызывается логическим оператором ИЛИ. Если любой из двух операндов отличен от нуля, тогда условие становится истинным. (A || B) истинно.
! Вызывается логическим оператором NOT. Используется для изменения логического состояния операнда. Если условие истинно, то логический оператор NOT сделает ложным. ! (A && B) истинно.

Побитовые операторы

Побитовый оператор работает с битами и выполняет побитовую операцию. Таблицы истинности для &, |, и ^ заключаются в следующем:

p q p & q p | q p ^ q
0 0 0 0 0
0 1 0 1 1
1 1 1 1 0
1 0 0 1 1

Побитовые операторы, поддерживаемые языком C ++, перечислены в следующей таблице:

Binary Ones Оператор дополнения является унарным и имеет эффект «flipping» бит. (

Операторы присваивания

Существуют следующие операторы присваивания, поддерживаемые языком C ++:

Оператор Описание Пример
знак равно Простой оператор присваивания, присваивает значения из правых операндов в левый операнд. C = A + B присваивает значение A + B в C
+ = Оператор Add AND присваивания, Он добавляет правый операнд в левый операнд и присваивает результат левому операнду. C + = A эквивалентно C = C + A
знак равно Subtract AND assign operator, вычитает правый операнд из левого операнда и присваивает результат левому операнду. C — = A эквивалентно C = C — A
знак равно Оператор умножения и присваивания, Он умножает правый операнд на левый операнд и присваивает результат левому операнду. C * = A эквивалентно C = C * A
знак равно Оператор Divide AND assign. Он делит левый операнд на правый операнд и присваивает результат левому операнду. C / = A эквивалентно C = C / A
знак равно Модуль и оператор присваивания, он принимает модуль с использованием двух операндов и присваивает результат левому операнду. C% = A эквивалентно C = C% A
<< = Оператор сдвига слева и. C << = 2 совпадает с C = C << 2
>> = Оператор правой смещения и назначения. C >> = 2 совпадает с C = C >> 2
знак равно Побитовый И оператор присваивания. C & = 2 является таким же, как C = C & 2
^ = Побитовое исключающее ИЛИ и оператор присваивания. C ^ = 2 является таким же, как C = C ^ 2
| = Побитовое включение оператора OR и присваивания. C | = 2 совпадает с C = C |2

Другие операторы

В следующей таблице перечислены некоторые другие операторы, поддерживаемые C ++:

Возвращает размер переменной. Например, sizeof (a), где 'a' является целым числом и будет возвращать 4.

Если Условие истинно, то оно возвращает значение X, иначе возвращает значение Y.

Вызывает последовательность операций. Значение всего выражения запятой — это значение последнего выражения списка, разделенного запятыми.

Используются для ссылки на отдельных членов классов, структур и союзов.

Преобразуют один тип данных в другой. Например, int (2.2000) вернет 2.

Возвращает адрес переменной. Например, & a; даст фактический адрес переменной.

Является указателем на переменную. Например * var; будет указывать на переменную var.

Приоритеты операторов в C ++

Приоритет оператора определяет группировку терминов в выражении. Это влияет на оценку выражения. Некоторые операторы имеют более высокий приоритет, чем другие; например, оператор умножения имеет более высокий приоритет, чем оператор сложения —

Например, x = 7 + 3 * 2; здесь x назначается 13, а не 20, потому что оператор * имеет более высокий приоритет, чем +, поэтому он сначала умножается на 3 * 2, а затем добавляется в 7.

Здесь операторы с наивысшим приоритетом появляются в верхней части таблицы, а нижние — внизу. Внутри выражения сначала будут оцениваться операторы с более высоким приоритетом.

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *