WikiSort.ru - Программирование

ПОИСК ПО САЙТУ | о проекте

Язык программирования C++, поддерживает все операторы своего прародителя Си и дополнен новыми операторами и возможностями.

После вычисления первого операнда для неперегруженных операторов «&&», «||» и «,» (оператор «запятая», англ. comma) компилятор вставляет точку следования (англ. sequence point), гарантирующую, что все побочные эффекты (например, оператор «постфиксный ++») будут выполнены до начала вычисления второго операнда.

Языки с Си-подобным синтаксисом (например, Java, C#, PHP и другие) часто заимствуют операторы Cи/C++ с сохранением не только поведения, но также приоритета и ассоциативности.

Таблицы

В таблицах используются следующие обозначения:

  • «a», «b» и «c»: имена объектов или значения (литералы, значения переменных, возвращаемые значения, lvalue);
  • «Перегружаемый»: возможность перегрузки оператора в языке C++;
  • «Реализован в Си»: существование оператора в языке Си;
  • «R», «T», «S»: имена типов;
  • «Пример»: пример объявления перегруженного оператора;
  • «Член типа T»: определение оператора в виде метода структуры или класса (внутри структуры или класса); пример:
struct T { // или class
   operator float () const;
};
T::operator float () const { /* реализация */ };
  • «Определение вне класса»: определение оператора в виде функции; пример:
#include <iostream>
struct T { // или class
   /* ... */
};
std::ostream & operator << ( std::ostream & a, T const & b ) { /* реализация */ }
  • «Н/Д»: недоступно.

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

Операция (выражение) Оператор Синтаксис выражения Перегружаемый Реализован в Си Пример
Член типа T Определение вне класса
Присваивание =a = bДаДа R& T::operator =(S b); н/д
Сложение +a + bДаДа R T::operator +(S b); R operator +(T a, S b);
Вычитание -a - bДаДа R T::operator -(S b); R operator -(T a, S b);
Унарный плюс ++aДаДа R T::operator +(); R operator +(T a);
Унарный минус --aДаДа R T::operator -(); R operator -(T a);
Умножение *a * bДаДа R T::operator *(S b); R operator *(T a, S b);
Деление /a / bДаДа R T::operator /(S b); R operator /(T a, S b);
Операция модуль (остаток от деления целых чисел)[note 1] %a % bДаДа R T::operator %(S b); R operator %(T a, S b);
Инкремент префиксный ++ ++a Да Да R& T::operator ++(); R& operator ++(T a);
суффиксный (постфиксный) ++ a++ Да Да R T::operator ++(int); R operator ++(T a, int);
[note 2]
Декремент префиксный -- --aДаДа R& T::operator --(); R& operator --(T a);
суффиксный (постфиксный) -- a--ДаДа R T::operator --(int); R operator --(T a, int);
[note 2]

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

Операция (выражение) Оператор Синтаксис выражения Перегружаемый Реализован в Си Пример
Член типа T Определение вне класса
Равенство ==a == b Да Да R T::operator ==(S b); R operator ==(T a, S b);
Неравенство !=a != bДаДа R T::operator !=(S b); R operator !=(T a, S b);
Больше >a > bДаДа R T::operator >(S b); R operator >(T a, S b);
Меньше <a < bДаДа R T::operator <(S b); R operator <(T a, S b);
Больше или равно >=a >= bДаДа R T::operator >=(S b); R operator >=(T a, S b);
Меньше или равно <=a <= bДаДа R T::operator <=(S b); R operator <=(T a, S b);

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

Операция (выражение) Оператор Синтаксис выражения Перегружаемый Реализован в Си Пример
Член типа T Определение вне класса
Логическое отрицание, НЕ !!a Да Да R T::operator !(); R operator !(T a);
Логическое умножение, И &&a && bДаДа R T::operator &&(S b); R operator &&(T a, S b);
Логическое сложение, ИЛИ ||a || bДаДа R T::operator ||(S b); R operator ||(T a, S b);

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

Операция (выражение) Оператор Синтаксис выражения Перегружаемый Реализован в Си Пример
Член типа T Определение вне класса
Побитовая инверсия ~~a Да Да R T::operator ~(); R operator ~(T a);
Побитовое И &a & bДаДа R T::operator &(S b); R operator &(T a, S b);
Побитовое ИЛИ (or) |a | bДаДа R T::operator |(S b); R operator |(T a, S b);
Побитовое исключающее ИЛИ (xor) ^a ^ bДаДа R T::operator ^(S b); R operator ^(T a, S b);
Побитовый сдвиг влево[note 3] <<a << bДаДа R T::operator <<(S b); R operator <<(T a, S b);
Побитовый сдвиг вправо[note 3][note 4] >>a >> bДаДа R T::operator >>(S b); R operator >>(T a, S b);

Составное присваивание

Операция (выражение) Оператор Синтаксис выражения Значение Перегружаемый Реализован в Си Пример
Член типа T Определение вне класса
Сложение, совмещённое с присваиванием +=a += b a = a + b Да Да R T::operator +=(S b); R operator +=(T a, S b);
Вычитание, совмещённое с присваиванием -=a -= b a = a - b Да Да R T::operator -=(S b); R operator -=(T a, S b);
Умножение, совмещённое с присваиванием *=a *= b a = a * b Да Да R T::operator *=(S b); R operator *=(T a, S b);
Деление, совмещённое с присваиванием /=a /= b a = a / b Да Да R T::operator /=(S b); R operator /=(T a, S b);
Вычисление остатка от деления, совмещённое с присваиванием[note 1] %=a %= b a = a % b Да Да R T::operator %=(S b); R operator %=(T a, S b);
Побитовое «И» (AND), совмещённое с присваиванием &=a &= b a = a & b Да Да R T::operator &=(S b); R operator &=(T a, S b);
Побитовое «ИЛИ» (or), совмещённое с присваиванием |=a |= b a = a | b Да Да R T::operator |=(S b); R operator |=(T a, S b);
Побитовое «исключающее ИЛИ» (xor), совмещённое с присваиванием ^=a ^= b a = a ^ b Да Да R T::operator ^=(S b); R operator ^=(T a, S b);
Побитовый сдвиг влево, совмещённый с присваиванием <<=a <<= b a = a << b Да Да R T::operator <<=(S b); R operator <<=(T a, S b);
Побитовый сдвиг вправо, совмещённый с присваиванием[note 4] >>=a >>= b a = a >> b Да Да R T::operator >>=(S b); R operator >>=(T a, S b);

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

Оператор Синтаксис Перегружаемый Реализован в Си Пример
Член типа T Определение вне класса
Обращение к элементу массива a[b] Да Да R T::operator [](S b);
н/д
Непрямое обращение («объект, на который указывает a») *aДаДа R T::operator *(); R operator *(T a);
Ссылка («адрес a») &aДаДа R T::operator &(); R operator &(T a);
Обращение к члену структуры («член b объекта, на который указывает a») a->bДаДа R* T::operator ->(); [note 5]
н/д
Обращение к члену структуры («член b объекта a») a.bНетДа н/д
Член, на который указывает b в объекте, на который указывает a[note 6] a->*bДаНет R T::operator ->*(S b); R operator ->*(T a, S b);
Член, на который указывает b в объекте a a.*bНетНет н/д

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

Оператор Синтаксис Перегружаемый Реализован в Си Пример
Член типа T Определение вне класса
Функтор a(a1, a2) Да Да R T::operator ()(S a1, U a2, ...); н/д
Оператор «запятая» a, bДаДа R T::operator ,(S b); R operator ,(T a, S b);
Тернарная условная операция a ? b : cНетДа н/д
Оператор расширения области видимости a::bНетНет н/д
Sizeof (размер) sizeof(a)[note 7]
sizeof(type)
НетДа н/д
Align-of (выравнивание) alignof(type) или _Alignof(type)[note 8]НетДа н/д
Интроспекция typeid(a)
typeid(type)
НетНет н/д
Приведение типа (type) aДаДа T::operator R(); н/д
[note 9]
Выделение памяти new typeДаНет void* T::operator new(size_t x); void* operator new(size_t x);
Выделение памяти для массива new type[n]ДаНет void* T::operator new[](size_t x); void* operator new[](size_t x);
Освобождение памяти delete aДаНет void T::operator delete(void* x); void operator delete(void* x);
Освобождение памяти, занятой массивом delete[] aДаНет void T::operator delete[](void* x); void operator delete[](void* x);

Примечания:

  1. 1 2 Оператор «%» работает только с целыми числами. Для чисел с плавающей точкой используйте функцию fmod () из файла «math.h».
  2. 1 2 Чтобы отличить префиксный и суффиксный (постфиксный) операторы друг от друга, у постфиксных операторов добавлен неиспользуемый формальный параметр типа int . Часто этому параметру даже не дают имя.
  3. 1 2 В библиотеке «iostream» операторы «<< » и «>> » используются для работы с потоковым выводом и вводом.
  4. 1 2 По стандарту C99, сдвиг вправо на отрицательное число — implementation defined behavior (см. неуточняемое поведение). Многие компиляторы, в том числе gcc (см. документацию (англ.)), реализуют арифметический сдвиг, но стандарт не запрещает реализовывать логический сдвиг.
  5. Тип возвращаемого значения оператора «operator->() » должен быть типом, к которому применим оператор «-> », например, указателем. Если «x » имеет тип «C », и класс «C » перегружает оператор «operator->() », выражение «x->y » раскрывается как «x.operator->()->y ».
  6. См. пример в статье (англ.) «Реализация оператора ->* для умных указателей» Скотта Майерса из журнала «Dr. Dobb’s journal», выпуск за октябрь 1999 года.
  7. Оператор sizeof , обычно, записывают со скобками. Если операнд — имя переменной, указание скобок необязательно. Если операнд — имя типа, скобки обязательны.
  8. Стандарт языка C++ определяет оператор alignof. Аналогичный оператор в стандарте языка Си называется _Alignof.
  9. Для оператора приведения типа тип возвращаемого значения явно не указывается, так как совпадает с именем оператора.

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

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


Этой таблицы приоритетов в большинстве случаев бывает достаточно, за исключением следующих случаев. Тернарный оператор «?:» может содержать в среднем выражении оператор «запятая» или присваивание, но код «a ? b, c : d » компилятор воспринимает как «a ? (b, c) : d », а не как бессмысленное выражение «(a ? b), (c : d) ». Таким образом выражение между ? и : воспринимается, как если бы оно было в скобках.

Приоритет Оператор Описание Ассоциативность
1

Наивысший

:: Раскрытие области видимости Нет
2 ++ Суффиксный инкремент Слева направо
-- Суффиксный декремент
() Вызов функции
[] Взятие элемента массива
. Выбор элемента по ссылке
-> Выбор элемента по указателю
typeid() RTTI (только C++; см typeid)
const_cast Приведение типа (C++) (см const cast)
dynamic_cast Приведение типа (C++) (см dynamic cast)
reinterpret_cast Каламбур типизации (C++) (см reinterpret_cast)
static_cast Приведение типа (C++) (см static cast)
3 ++ Префиксный инкремент Справа налево
-- Префиксный декремент
+ Унарный плюс
- Унарный минус
! Логическое НЕ
~ Побитовое НЕ
(type) Приведение типа
* Разыменование указателя
& Взятие адреса объекта
sizeof Sizeof (размер)
new, new[] Выделение динамической памяти (C++)
delete, delete[] Освобождение динамической памяти (C++)
4 .* Указатель на член (C++) Слева направо
->* Указатель на член (C++)
5 * Умножение
/ Деление
% Получение остатка от деления
6 + Сложение
- Вычитание
7 << Побитовый сдвиг влево
>> Побитовый сдвиг вправо
8 < Меньше
<= Меньше или равно
> Больше
>= Больше или равно
9 == Равенство
!= Неравенство
10 & Побитовое И (and)
11 ^ Побитовое исключающее ИЛИ (xor)
12 | Побитовое ИЛИ (or)
13 && Логическое И
14 || Логическое ИЛИ
15 ?: Тернарная условная операция Справа налево
16 = Присваивание
+= Сложение, совмещённое с присваиванием
-= Вычитание, совмещённое с присваиванием
*= Умножение, совмещённое с присваиванием
/= Деление, совмещённое с присваиванием
%= Вычисление остатка от деления, совмещённое с присваиванием
<<= Побитовый сдвиг влево, совмещённый с присваиванием
>>= Побитовый сдвиг вправо, совмещённый с присваиванием
&= Побитовое «И», совмещённое с присваиванием
|= Побитовое «ИЛИ», совмещённое с присваиванием
^= Побитовое «исключающее ИЛИ» (xor), совмещённое с присваиванием
17 throw Оператор создания исключения (C++)
18 , Оператор «запятая» Слева направо

Описание

Компилятор использует таблицу приоритетов для определения порядка вычисления операторов.

  • Например, ++x*3 был бы двусмысленным без каких-либо правил приоритетов. По таблице можно сказать, что x сначала связывается с оператором ++, и только затем с оператором *, поэтому независимо от действия оператора ++, это действие только над x (а не над x*3). Таким образом, выражение эквивалентно (++x, x*3).
  • Аналогично с кодом 3*x++, где таблица утверждает, что инкремент применяется только к x а не к 3*x. Функционально это выражение эквивалентно (tmp=x, x++, tmp=3*tmp, tmp), если выразить временную переменную как tmp.
Приоритеты и связывание

Связывание операторов в стандартах Си и C++ определено через грамматику языка, а не через таблицу. Это может создать конфликт. Например, в языке Си синтаксис условного оператора таков:

logical-OR-expression ? expression : conditional-expression

А в языке C++:

logical-OR-expression ? expression : assignment-expression

Из-за этого выражение:

e = a < d ? a++ : a = d

будет воспринято по-разному в этих двух языках. В Си выражение синтаксически некорректно, но многие компиляторы воспринимают его как:

e = ((a < d ? a++ : a) = d)

Этот вариант ошибочен, так как результат условного оператора не может служить lvalue (то есть, левой частью оператора присваивания).

В C++, выражение будет разобрано как корректное:

e = (a < d ? a++ : (a = d))

Приоритеты побитовых логических операторов несколько неинтуитивны[1]. Концептуально & и | являются такими же арифметическими операторами как * и + соответственно.

Выражение a & b == 7 синтаксически воспринимается как a & (b == 7) , но выражение a + b == 7 эквивалентно (a + b) == 7 . Из-за этого часто требуется пользоваться скобками для явного задания порядка вычислений.

Синонимы операторов в C++

В стандарте C++ определены[2] диграфы для некоторых операторов:

ДиграфЭквивалентная строка
and&&
bitand&
and_eq&=
or||
bitor|
or_eq|=
xor^
xor_eq^=
not!
not_eq!=
compl~

Диграфы могут использоваться точно так же как и операторы, являются синонимами операторов. Например, диграф «bitand » может использоваться для замены операторов «побитовое И» и «получение адреса» или в определении ссылочных типов. Так, код «int bitand ref = n; » эквивалентен коду «int & ref = n; ».

Стандарт ANSI/ISO C определяет перечисленные диграфы в виде констант #define (см. препроцессор). Константы определены в заголовочном файле «iso646.h». Для совместимости с Си стандарт C++ определяет фиктивный заголовочный файл «ciso646».

Примечания

  1. Chistory
  2. ISO/IEC JTC1/SC22/WG21 - Комитет по стандартизации C++. ISO/IEC 14882:1998(E) Язык программирования C++ (англ.). — Международная группа по стандартизации языка программирования C++, 1 сентября 1998 года. — P. 40–41.

Ссылки

  • Статья (англ.) «Операторы C++» на сайте cppreference.com.
  • Статья (англ.) «Префиксные и постфиксные операторы в языках Си и C++» на сайте msdn.microsoft.com.
  • ISO/IEC 14882

Данная страница на сайте WikiSort.ru содержит текст со страницы сайта "Википедия".

Если Вы хотите её отредактировать, то можете сделать это на странице редактирования в Википедии.

Если сделанные Вами правки не будут кем-нибудь удалены, то через несколько дней они появятся на сайте WikiSort.ru .




Текст в блоке "Читать" взят с сайта "Википедия" и доступен по лицензии Creative Commons Attribution-ShareAlike; в отдельных случаях могут действовать дополнительные условия.

Другой контент может иметь иную лицензию. Перед использованием материалов сайта WikiSort.ru внимательно изучите правила лицензирования конкретных элементов наполнения сайта.

2019-2024
WikiSort.ru - проект по пересортировке и дополнению контента Википедии