Operators
An operator is a symbol or symbolic sequence that performs an operation on one or more operands and returns a result. a + b, !flag, x = 5 — these are all operators.
In C++, operators are classified by the number of operands:
- unary — one operand (
++x,-a,!flag) - binary — two operands (
a + b,a && b) - ternary — three operands (
cond ? a : b)
Unary operators
Work on a single operand.
| Operator | Description | Example |
|---|---|---|
++x | Pre-increment: increments x, returns the new value | int y = ++x; |
x++ | Post-increment: returns the old value, then increments | int y = x++; |
--x | Pre-decrement | int y = --x; |
x-- | Post-decrement | int y = x--; |
-x | Unary minus (negation) | -5 |
!x | Logical NOT | !true == false |
~x | Bitwise NOT (one's complement) | ~0 == -1 |
&x | Address-of | int* p = &x; |
*p | Pointer dereference | int v = *p; |
sizeof(x) | Size in bytes (compile-time) | sizeof(int) == 4 |
Pre-increment vs post-increment
int a = 5;
int b = ++a; // a = 6, b = 6 (incremented BEFORE use)
int c = a++; // a = 7, c = 6 (used, then incremented)
For iterators and non-trivial objects, ++it is preferable — post-increment creates a temporary copy of the object. See the Unary operators section for details.
Binary arithmetic operators
| Operator | Operation | Note |
|---|---|---|
a + b | Addition | |
a - b | Subtraction | |
a * b | Multiplication | |
a / b | Division | Integer if both are int: 7/2 == 3 |
a % b | Remainder | Integers only: 7%2 == 1 |
int x = 7, y = 2;
std::cout << x / y; // 3 (integer division)
std::cout << x % y; // 1
double d = 7.0 / 2; // 3.5 (floating-point division)
Comparison operators
| Operator | Meaning |
|---|---|
a == b | equal |
a != b | not equal |
a < b | less than |
a > b | greater than |
a <= b | less than or equal |
a >= b | greater than or equal |
All return bool. Since C++20 the <=> (spaceship operator) has been added — it returns the comparison ordering and lets the rest of the operators be synthesized automatically:
struct Point {
int x, y;
auto operator<=>(const Point&) const = default; // C++20: everything else for free
};
Logical operators
| Operator | Meaning | Evaluation | ||
|---|---|---|---|---|
a && b | AND | Lazy: if a is false, b is not evaluated | ||
| `a \ | \ | b` | OR | Lazy: if a is true, b is not evaluated |
!a | NOT |
"Lazy" evaluation (short-circuit evaluation) is not just an optimization — it is a guarantee of the standard. This lets you safely write:
if (ptr != nullptr && ptr->value > 0) { } // ptr->value is not evaluated if ptr == nullptr
Bitwise operators
Work on the bits of integer values:
| Operator | Meaning | Example | ||
|---|---|---|---|---|
a & b | AND | 0b1100 & 0b1010 == 0b1000 | ||
| `a \ | b` | OR | `0b1100 \ | 0b1010 == 0b1110` |
a ^ b | XOR | 0b1100 ^ 0b1010 == 0b0110 | ||
~a | NOT (inversion) | ~0b0000 == 0b1111... | ||
a << n | Left shift | 1 << 3 == 8 | ||
a >> n | Right shift | 16 >> 2 == 4 |
uint8_t flags = 0b00000000;
flags |= (1 << 3); // set bit 3: flags == 0b00001000
flags &= ~(1 << 3); // clear bit 3: flags == 0b00000000
bool set = flags & (1 << 3); // test bit 3
A left shift by N is equivalent to multiplying by 2^N, a right shift to division (for unsigned values).
Assignment operators
x = 5; // simple assignment
x += 3; // x = x + 3
x -= 3; // x = x - 3
x *= 2; // x = x * 2
x /= 2; // x = x / 2
x %= 3; // x = x % 3
x &= 0xF; // x = x & 0xF
x |= 0x1; // x = x | 0x1
x ^= 0xFF; // x = x ^ 0xFF
x <<= 2; // x = x << 2
x >>= 1; // x = x >> 1
Ternary operator
int abs_x = (x >= 0) ? x : -x;
Unlike if-else, the ternary operator is an expression — you can use it wherever a value is needed: in a const initializer, a function argument, constexpr. See the Ternary operator section for details.
Precedence table (simplified)
Operator precedence
When in doubt, always add parentheses — they make the evaluation order explicit:
int x = 2 + 3 * 4; // 14 (multiplication above addition)
int y = (2 + 3) * 4; // 20 (parentheses raise precedence)
bool ok = a == b && c > 0; // == and > first, then &&
bool ok2 = (a == b) && (c > 0); // same thing, but more readable
Operator overloading
In C++ you can redefine the behavior of operators for user-defined types. This makes code expressive where the type models a mathematical or physical entity — a vector, a matrix, a fraction, a complex number.
struct Vector2 {
float x, y;
// Class method — the left operand is *this
Vector2 operator+(const Vector2& other) const {
return {x + other.x, y + other.y};
}
// Compound assignment returns *this by reference
Vector2& operator+=(const Vector2& other) {
x += other.x; y += other.y;
return *this;
}
};
Vector2 a{1, 2}, b{3, 4};
Vector2 c = a + b; // c == {4, 6}
When overloading is justified: the type represents a mathematical abstraction, and the operation is obvious without documentation. Vector + vector — obvious. Socket + socket — no.
Common overloading mistakes:
operator+returns*this(mutates the object) — that's what+=does, not+- Inconsistency:
+is implemented but there is no+=(or vice versa) operator==is implemented butoperator!=is not (before C++20 the compiler does not link them)
Overloading is covered in more detail in the Binary operators and OOP sections.
Interview relevance
Operators are a foundational topic that tests the precision of your knowledge, not surface-level familiarity.
What the interviewer checks:
- The difference between pre-increment and post-increment (especially for non-int types)
- Knowledge of short-circuit evaluation and the ability to use it to guard against UB
- Understanding of precedence — the classic
a & b == ctrap (where==is above&) - On overloading: why
operator+should be a free function orfriendfor symmetry; whatoperator+=returns - C++20: why
<=>is needed and what= defaultmeans for comparison operators
Popular question directions:
- How does
++itdiffer fromit++for an iterator? - What happens with
x & 0xFF == 0? (precedence — a trap) - Why can't
operator<<forstd::ostreambe a class member? - How do you implement the full set of comparison operators before C++20, and how does C++20 simplify this?
Common wrong answers:
- "Post-increment is faster" (the opposite — it creates a copy)
- "
&&and||always evaluate both operands" (no — short-circuit) - "
operator+mutates the left-hand object" (no — it returns a new object;operator+=mutates)