Дифференциальные операторы
- 1 year ago
- 0
- 0
Язык программирования C++ поддерживает все операторы своего прародителя Си и дополнен новыми операторами и возможностями.
После вычисления первого операнда для неперегруженных операторов « && », « || » и « , » (оператор «запятая», англ. comma ) компилятор вставляет точку следования ( англ. sequence point ), гарантирующую, что все побочные эффекты (например, оператор «постфиксный ++») будут выполнены до начала вычисления второго операнда.
Языки с Си-подобным синтаксисом (например, Java , C# , PHP и другие) часто заимствуют операторы Cи/C++ с сохранением не только поведения, но также приоритета и ассоциативности .
В таблицах используются следующие обозначения:
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
);
|
|
Операция модуль ( остаток от деления целых чисел) | % |
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
);
|
|
Декремент | префиксный |
--
|
--
a
|
Да | Да |
R
&
T
::
operator
--
();
|
R
&
operator
--
(
T
a
);
|
суффиксный (постфиксный) |
--
|
a
--
|
Да | Да |
R
T
::
operator
--
(
int
);
|
R
operator
--
(
T
a
,
int
);
|
|
Операция (выражение) | Оператор | Синтаксис выражения | Перегружаемый | Реализован в Си | Пример | |
---|---|---|---|---|---|---|
Член типа 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
);
|
Побитовый сдвиг влево |
<<
|
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
+=
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
);
|
Вычисление остатка от деления, совмещённое с присваиванием |
%=
|
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
);
|
Побитовый сдвиг вправо, совмещённый с присваиванием |
>>=
|
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
->
();
|
н/д | |
Обращение к члену структуры («член b объекта a ») |
a
.
b
|
Нет | Да | н/д | ||
Член, на который указывает b в объекте, на который указывает a |
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
|
Нет | Нет | н/д | ||
Пользовательские литералы (введены в C++11) |
"a"_b
|
Да | Нет | н/д |
R
operator
""
_b
(
T
a
)
|
|
(размер) |
sizeof
(a)
sizeof
(
type
)
|
Нет | Да | н/д | ||
( выравнивание ) |
alignof
(
type
)
или
_Alignof
(
type
)
|
Нет | Да | н/д | ||
Интроспекция |
typeid
(a)
typeid
(
type
)
|
Нет | Нет | н/д | ||
Приведение типа |
(
type
) a
|
Да | Да |
T
::
operator
R
();
|
н/д | |
Выделение памяти |
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
);
|
Примечания:
fmod
() из файла «
math.h
».
int
. Часто этому параметру даже не дают имя.
<<
» и «
>>
» используются для работы с потоковым выводом и вводом.
operator
->
()
» должен быть типом, к которому применим оператор «
->
», например, указателем. Если «
x
» имеет тип «
C
», и класс «
C
» перегружает оператор «
operator
->
()
», выражение «
x
->
y
» раскрывается как «
x
.
operator
->
()
->
y
».
->*
для
умных указателей
»
Скотта Майерса
из журнала «
Dr. Dobb’s journal
», выпуск за октябрь 1999 года.
sizeof
, обычно, записывают со скобками. Если операнд — имя переменной, указание скобок необязательно. Если операнд — имя типа, скобки обязательны.
alignof
. Аналогичный оператор в стандарте языка Си называется
_Alignof
.
В данной таблице указаны приоритеты операторов и их ассоциативность. Операторы, указанные в таблице выше (раньше), имеют более высокий приоритет (приоритет вычисления). При рассмотрении выражения, операторы, имеющие более высокий приоритет, будут вычислены раньше операторов с низким приоритетом. Если несколько операторов указаны в одной ячейке, то они имеют одинаковый приоритет и вычисляются в последовательности, задаваемой ассоциативностью. Приоритеты операторов не изменяются при их перегрузке.
Этой таблицы приоритетов в большинстве случаев бывает достаточно, за исключением следующих случаев. Тернарный оператор «?:» может содержать в среднем выражении оператор «запятая» или присваивание, но код «
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
|
(размер) | ||
new
,
new[]
|
Выделение динамической памяти (C++) | ||
delete
,
delete[]
|
Освобождение динамической памяти (C++) | ||
4 |
.*
|
Указатель на член (C++) | Слева направо |
->*
|
Указатель на член (C++) | ||
5 |
*
|
Умножение | |
/
|
Деление | ||
%
|
Получение остатка от деления | ||
6 |
+
|
Сложение | |
-
|
Вычитание | ||
7 |
<<
|
Побитовый сдвиг влево | |
>>
|
Побитовый сдвиг вправо | ||
8 |
<
|
Меньше | |
<=
|
Меньше или равно | ||
>
|
Больше | ||
>=
|
Больше или равно | ||
9 |
==
|
Равенство | |
!=
|
Неравенство | ||
10 |
&
|
Побитовое И (and) | |
11 |
^
|
Побитовое исключающее ИЛИ (xor) | |
12 |
|
|
Побитовое ИЛИ (or) | |
13 |
&&
|
Логическое И | |
14 |
||
|
Логическое ИЛИ | |
15 |
?:
|
Тернарная условная операция | Справа налево |
=
|
Присваивание | ||
+=
|
Сложение, совмещённое с присваиванием | ||
-=
|
Вычитание, совмещённое с присваиванием | ||
*=
|
Умножение, совмещённое с присваиванием | ||
/=
|
Деление, совмещённое с присваиванием | ||
%=
|
Вычисление остатка от деления, совмещённое с присваиванием | ||
<<=
|
Побитовый сдвиг влево, совмещённый с присваиванием | ||
>>=
|
Побитовый сдвиг вправо, совмещённый с присваиванием | ||
&=
|
Побитовое «И», совмещённое с присваиванием | ||
|=
|
Побитовое «ИЛИ», совмещённое с присваиванием | ||
^=
|
Побитовое «исключающее ИЛИ» (xor), совмещённое с присваиванием | ||
throw
|
Оператор создания исключения (C++) | ||
16 |
,
|
Оператор «запятая» | Слева направо |
Компилятор использует таблицу приоритетов для определения порядка вычисления операторов.
++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
будет воспринято по-разному в этих двух языках. В Си выражение синтаксически некорректно, так как результат условного оператора не может служить lvalue (то есть, левой частью оператора присваивания).
В C++, выражение будет разобрано как корректное:
e = (a < d ? a++ : (a = d))
Приоритеты побитовых логических операторов несколько неинтуитивны
. Концептуально
&
и
|
являются такими же арифметическими операторами как
*
и
+
соответственно.
Выражение
a
&
b
==
7
синтаксически воспринимается как
a
&
(
b
==
7
)
, но выражение
a
+
b
==
7
эквивалентно
(
a
+
b
)
==
7
. Из-за этого часто требуется пользоваться скобками для явного задания порядка вычислений.
В стандарте C++ определены диграфы для некоторых операторов:
Диграф | Эквивалентная строка |
---|---|
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
».