Skip to content

Operators

Arithmetic Operators

Operator Function
+ (unary) Positive
- (unary) Negative
* (binary) Multiplication
/ Division
% Modulo
+ (binary) Addition
- (binary) Subtraction
Unary and Binary Operators

A unary operator (also known as a monadic operator) is an operator that operates on a single operand, while a binary operator (also known as a dyadic operator) operates on two operands. For example, in 1 + 2, the plus sign is a binary operator with two operands 1 and 2. Additionally, C++ has a unique ternary operator ?:.

Among arithmetic operators, there are two unary operators (positive, negative) and five binary operators (multiplication, division, modulo, addition, subtraction), with unary operators having the highest precedence.

The modulo operator % calculates the remainder of dividing two integers.

When - is used as a binary operator, it acts as the subtraction operator, e.g., 2-1; when used as a unary operator, it acts as the negation operator, e.g., -1.

Usage example:

op=x-y*z

The computed value of op follows the precedence rules of mathematics for addition, subtraction, multiplication, and division. Operations with higher precedence are performed first; operations with the same precedence are evaluated according to their associativity. Parentheses can be used to increase precedence.

Type Conversion in Arithmetic Operations

For binary arithmetic operators, when the two participating variables have the same type, no type conversion occurs, and the result will be accommodated using the type of the variables. Otherwise, type conversion occurs to make the two variables' types consistent. The conversion rules are detailed in Type Conversion.

For example, for an integer (int) variable \(x\) and a double-precision floating-point (double) variable \(y\):

  • x/3 will result in an integer type;
  • x/3.0 will result in a double-precision floating-point type;
  • x/y will result in a double-precision floating-point type;
  • x*1/3 will result in an integer type;
  • x*1.0/3 will result in a double-precision floating-point type;

Bitwise Operators

Operator Function
~ Bitwise NOT
& (binary) Bitwise AND
| Bitwise OR
^ Bitwise XOR
<< Bitwise left shift
>> Bitwise right shift

For the meaning of bitwise operations, please refer to the Bit Operations page. Note that the precedence of bitwise operators is lower than that of ordinary arithmetic operators.

Increment/Decrement Operators

Sometimes we need to increase a variable by 1 (increment) or decrease it by 1 (decrement). This is where the increment operator ++ and decrement operator -- come in handy.

The increment/decrement operator can be placed before or after the variable. When placed before, it is called prefix; when placed after, it is called suffix. When used alone, there is no significant difference between prefix and suffix. However, if the value of the expression is needed, attention is required, as shown in the examples below. For more details, refer to the example section in References.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
i = 100;

op1 = i++;  // op1 = 100, first op1 = i, then i = i + 1

i = 100;

op2 = ++i;  // op2 = 101, first i = i + 1, then assign to op2

i = 100;

op3 = i--;  // op3 = 100, first assign to op3, then i = i - 1

i = 100;

op4 = --i;  // op4 = 99, first i = i - 1, then assign to op4

Compound Assignment Operators

Compound assignment operators are essentially shorthand forms of expressions. They can be divided into compound arithmetic operators +=, -=, *=, /=, %= and compound bitwise operators &=, |=, ^=, <<=, >>=.

For example, op = op + 2 can be written as op += 2, op = op - 2 as op -= 2, and op = op * 2 as op *= 2.

Conditional Operator

The conditional operator can be seen as a shorthand for an if statement. In a ? b : c, if expression a evaluates to true, the result of the conditional expression is b; otherwise, it is c.

Comparison Operators

Operator Function
> Greater than
>= Greater than or equal to
< Less than
<= Less than or equal to
== Equal to
!= Not equal to

It is particularly important to distinguish between the equality operator == and the assignment operator =, especially in conditional statements.

if (op=1) and if (op==1) may look similar, but their functions are vastly different. The first statement assigns a value to op. If the assigned value is non-zero, it is considered true, so the condition is always satisfied, failing to serve as a proper check. The second statement correctly checks the value of op.

Logical Operators

Operator Function
&& Logical AND
|| Logical OR
! Logical NOT

1
2
3
4
5
Result = op1 && op2;  // Result is true only when both op1 and op2 are true

Result = op1 || op2;  // Result is true if at least one of op1 or op2 is true

Result = !op1;  // Result is true when op1 is false

The built-in operators && and || perform short-circuit evaluation (if the result is known after evaluating the first operand, the second is not evaluated). Overloaded operators do not have this property and always evaluate both operands.

Comma Operator

The comma operator can separate multiple expressions. The separated expressions are evaluated from left to right, and the value of the entire expression is the value of the last expression. The comma operator has the lowest precedence among all operators.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
exp1, exp2, exp3;  // The final value is the result of exp3.

Result = 1 + 2, 3 + 4, 5 + 6;
// The value of Result is 3, not 11, because the assignment operator "="
// has higher precedence than the comma operator, so assignment occurs before comma evaluation.

Result = (1 + 2, 3 + 4, 5 + 6);

// To make Result hold the result of the comma expression, the entire expression must be parenthesized to raise its precedence.
// Now Result's value is 11.

Member Access Operators

Operator Function
[] Array subscript
. Object member access
& (unary) Address-of / Get reference
* (unary) Indirection / Dereference
-> Pointer member access

These operators are used to access object members or memory. All except the last can be overloaded. For content related to &, *, and ->, please read the Pointers and References tutorials. Two rarely used operators, .* and ->*, are omitted here; their usage can be found in the C++ Language Reference.

1
2
3
4
5
auto result1 = v[1];  // Get the object at index 2 in v
auto result2 = p.q;   // Get member q of object p
auto result3 = p -> q;  // Get member q of the object pointed to by pointer p, equivalent to (*p).q
auto result4 = &v;      // Get a pointer to v
auto result5 = *v;      // Get the object pointed to by pointer v

Complete C++ Operator Precedence Table

From C++ Operator Precedence - cppreference, modified.

Operator Description Example Overloadable
Level 1
:: Scope resolution Class::age = 2; Not overloadable
Level 2
++ Post-increment for (int i = 0; i < 10; i++) cout << i; Overloadable
-- Post-decrement for (int i = 10; i > 0; i--) cout << i; Overloadable
type() type{} Type cast unsigned int a = unsigned(3.14); Overloadable
() Function call isdigit('1') Overloadable
[] Array subscript array[4] = 2; Overloadable
. Object member access obj.age = 34; Not overloadable
-> Pointer member access ptr->age = 34; Overloadable
Level 3 (Right-to-left associativity)
++ Pre-increment for (i = 0; i < 10; ++i) cout << i; Overloadable
-- Pre-decrement for (i = 10; i > 0; --i) cout << i; Overloadable
+ Unary plus int i = +1; Overloadable
- Unary minus int i = -1; Overloadable
! Logical NOT if (!done) … Overloadable
~ Bitwise NOT flags = ~flags; Overloadable
(type) C-style type cast int i = (int) floatNum; Overloadable
* Indirection int data = *intPtr; Overloadable
& Address-of int *intPtr = &data; Overloadable
sizeof Size of type int size = sizeof floatNum; int size = sizeof(float); Not overloadable
new Dynamic memory allocation for object long *pVar = new long; MyClass *ptr = new MyClass(args); Overloadable
new [] Dynamic memory allocation for array long *array = new long[n]; Overloadable
delete Dynamic memory deallocation for object delete pVar; Overloadable
delete [] Dynamic memory deallocation for array delete [] array; Overloadable
Level 4
.* Pointer to member of object obj.*var = 24; Not overloadable
->* Pointer to member via pointer ptr->*var = 24; Overloadable
Level 5
* Multiplication int i = 2 * 4; Overloadable
/ Division float f = 10.0 / 3.0; Overloadable
% Modulo (remainder) int rem = 4 % 3; Overloadable
Level 6
+ Addition int i = 2 + 3; Overloadable
- Subtraction int i = 5 - 1; Overloadable
Level 7
<< Bitwise left shift int flags = 33 << 1; Overloadable
>> Bitwise right shift int flags = 33 >> 1; Overloadable
Level 8
<=> Three-way comparison operator if ((i <=> 42) < 0) ... Overloadable
Level 9
< Less than if (i < 42) ... Overloadable
<= Less than or equal to if (i <= 42) ... Overloadable
> Greater than if (i > 42) ... Overloadable
>= Greater than or equal to if (i >= 42) ... Overloadable
Level 10
== Equal to if (i == 42) ... Overloadable
!= Not equal to if (i != 42) ... Overloadable
Level 11
& Bitwise AND flags = flags & 42; Overloadable
Level 12
^ Bitwise XOR flags = flags ^ 42; Overloadable
Level 13
| Bitwise OR flags = flags | 42; Overloadable
Level 14
&& Logical AND if (conditionA && conditionB) ... Overloadable
Level 15
|| Logical OR if (conditionA || conditionB) ... Overloadable
Level 16 (Right-to-left associativity)
? : Conditional operator int i = a > b ? a : b; Not overloadable
throw Exception throw throw EClass("Message"); Not overloadable
= Assignment int a = b; Overloadable
+= Addition assignment a += 3; Overloadable
-= Subtraction assignment b -= 4; Overloadable
*= Multiplication assignment a *= 5; Overloadable
/= Division assignment a /= 2; Overloadable
%= Modulo assignment a %= 3; Overloadable
<<= Bitwise left shift assignment flags <<= 2; Overloadable
>>= Bitwise right shift assignment flags >>= 2; Overloadable
&= Bitwise AND assignment flags &= new_flags; Overloadable
^= Bitwise XOR assignment flags ^= new_flags; Overloadable
|= Bitwise OR assignment flags |= new_flags; Overloadable
Level 17
, Comma separator for (i = 0, j = 0; i < 10; i++, j++) ... Overloadable

Note that operators such as const_cast, static_cast, dynamic_cast, reinterpret_cast, typeid, sizeof..., noexcept, and alignof are not listed in the table because their usage resembles function calls and does not cause ambiguity.