All Courses
Foundations

Operators in C++


Introduction

Operators are special symbols that perform operations on operands (variables and values). C++ provides a rich set of operators that can be categorized based on their functionality.

Types of Operators in C++

Category Operators Description
Arithmetic +, -, *, /, % Mathematical operations
Relational ==, !=, <, >, <=, >= Comparison operations
Logical &&, \|\|, ! Boolean logic
Bitwise &, \|, ^, ~, <<, >> Bit manipulation
Assignment =, +=, -=, *=, /=, etc. Value assignment
Increment/Decrement ++, -- Increase/decrease by 1
Ternary ? : Conditional expression
Others sizeof, ,, ::, ->, . Special operations

Arithmetic Operators

Arithmetic operators perform mathematical calculations on numeric operands.

Basic Arithmetic Operators

Operator Name Example Result
+ Addition 5 + 3 8
- Subtraction 5 - 3 2
* Multiplication 5 * 3 15
/ Division 5 / 3 1 (integer)
% Modulus 5 % 3 2

Integer Division vs Float Division

#include <iostream>
using namespace std;

int main() {
    // Integer division - truncates decimal
    int a = 7, b = 3;
    cout << "7 / 3 = " << a / b << endl;        // Output: 2

    // Float division - preserves decimal
    double x = 7.0, y = 3.0;
    cout << "7.0 / 3.0 = " << x / y << endl;    // Output: 2.33333

    // Mixed division
    cout << "7 / 3.0 = " << a / y << endl;      // Output: 2.33333 (int promoted to double)

    return 0;
}

Modulus Operator

The modulus operator % returns the remainder of integer division:

int remainder = 17 % 5;   // remainder = 2 (17 = 5*3 + 2)
int even_check = 10 % 2;  // even_check = 0 (10 is even)
int odd_check = 11 % 2;   // odd_check = 1 (11 is odd)

Guide: Modulus only works with integers. For floating-point, use fmod() from <cmath>.

Unary Plus and Minus

int a = 5;
int b = -a;    // b = -5 (unary minus)
int c = +a;    // c = 5 (unary plus, rarely used)
int d = -(-a); // d = 5 (double negative)

Relational Operators

Relational operators compare two values and return a boolean result (true or false).

Comparison Operators

Operator Meaning Example Result
== Equal to 5 == 5 true
!= Not equal to 5 != 3 true
< Less than 3 < 5 true
> Greater than 5 > 3 true
<= Less than or equal 5 <= 5 true
>= Greater than or equal 5 >= 3 true

Usage Examples

#include <iostream>
using namespace std;

int main() {
    int x = 10, y = 20;

    cout << boolalpha;  // Print "true"/"false" instead of 1/0

    cout << "x == y: " << (x == y) << endl;  // false
    cout << "x != y: " << (x != y) << endl;  // true
    cout << "x < y: " << (x < y) << endl;    // true
    cout << "x > y: " << (x > y) << endl;    // false
    cout << "x <= y: " << (x <= y) << endl;  // true
    cout << "x >= y: " << (x >= y) << endl;  // false

    return 0;
}

Comparing Floating-Point Numbers

Warning: Direct comparison of floating-point numbers can be unreliable due to precision issues.

#include <cmath>

double a = 0.1 + 0.2;
double b = 0.3;

// BAD: Direct comparison
if (a == b) { /* may not work! */ }

// GOOD: Use epsilon comparison
const double EPSILON = 1e-9;
if (fabs(a - b) < EPSILON) {
    cout << "Numbers are approximately equal" << endl;
}

Three-Way Comparison (C++20)

C++20 introduces the spaceship operator <=>:

#include <compare>

int a = 5, b = 10;
auto result = a <=> b;

if (result < 0)  cout << "a is less than b";
if (result == 0) cout << "a equals b";
if (result > 0)  cout << "a is greater than b";

Logical Operators

Logical operators combine boolean expressions.

Truth Tables

AND Operator (&&)

A B A && B
false false false
false true false
true false false
true true true

OR Operator (||)

A B A || B
false false false
false true true
true false true
true true true

NOT Operator (!)

A !A
false true
true false

Short-Circuit Evaluation

C++ uses short-circuit evaluation for logical operators:

int x = 0;

// AND: If first operand is false, second is not evaluated
if (x != 0 && 10 / x > 1) {
    // Safe: 10/x won't execute when x is 0
}

// OR: If first operand is true, second is not evaluated
if (x == 0 || 10 / x > 1) {
    // Safe: 10/x won't execute when x is 0
}

Practical Examples

int age = 25;
bool hasLicense = true;
bool hasInsurance = true;

// Multiple conditions
if (age >= 18 && hasLicense && hasInsurance) {
    cout << "Can drive legally" << endl;
}

// Either condition
if (age < 13 || age >= 65) {
    cout << "Eligible for discount" << endl;
}

// Negation
if (!hasLicense) {
    cout << "Cannot drive" << endl;
}

Bitwise Operators

Bitwise operators work on individual bits of integer values.

Bitwise Operators Overview

Operator Name Description
& AND Sets bit to 1 if both bits are 1
\| OR Sets bit to 1 if at least one bit is 1
^ XOR Sets bit to 1 if bits are different
~ NOT Inverts all bits
<< Left shift Shifts bits left, fills with 0
>> Right shift Shifts bits right

Bitwise AND (&)

    5 = 0101
    3 = 0011
    --------
5 & 3 = 0001 = 1
int result = 5 & 3;  // result = 1

Bitwise OR (|)

    5 = 0101
    3 = 0011
    --------
5 | 3 = 0111 = 7
int result = 5 | 3;  // result = 7

Bitwise XOR (^)

    5 = 0101
    3 = 0011
    --------
5 ^ 3 = 0110 = 6
int result = 5 ^ 3;  // result = 6

// XOR swap trick (without temp variable)
int a = 5, b = 3;
a = a ^ b;  // a = 6
b = a ^ b;  // b = 5
a = a ^ b;  // a = 3

Bitwise NOT (~)

int a = 5;      // Binary: 00000101
int b = ~a;     // Binary: 11111010 = -6 (two's complement)

Left Shift (<<)

int a = 5;           // Binary: 00000101
int b = a << 1;      // Binary: 00001010 = 10
int c = a << 2;      // Binary: 00010100 = 20

// Left shift by n is equivalent to multiplying by 2^n
// a << n == a * 2^n

Right Shift (>>)

int a = 20;          // Binary: 00010100
int b = a >> 1;      // Binary: 00001010 = 10
int c = a >> 2;      // Binary: 00000101 = 5

// Right shift by n is equivalent to dividing by 2^n
// a >> n == a / 2^n

Practical Applications

// Check if number is odd or even
bool isOdd = (n & 1);  // Last bit is 1 for odd numbers

// Set a bit at position pos
int setBit = n | (1 << pos);

// Clear a bit at position pos
int clearBit = n & ~(1 << pos);

// Toggle a bit at position pos
int toggleBit = n ^ (1 << pos);

// Check if bit at position pos is set
bool isBitSet = (n & (1 << pos)) != 0;

Assignment Operators

Assignment operators assign values to variables.

Simple Assignment

int x = 10;       // Assign 10 to x
int y = x;        // Assign value of x to y
int a, b, c;
a = b = c = 5;    // Chained assignment (right to left)

Compound Assignment Operators

Operator Example Equivalent
+= x += 5 x = x + 5
-= x -= 5 x = x - 5
*= x *= 5 x = x * 5
/= x /= 5 x = x / 5
%= x %= 5 x = x % 5
&= x &= 5 x = x & 5
\|= x \|= 5 x = x \| 5
^= x ^= 5 x = x ^ 5
<<= x <<= 2 x = x << 2
>>= x >>= 2 x = x >> 2
int x = 10;

x += 5;   // x = 15
x -= 3;   // x = 12
x *= 2;   // x = 24
x /= 4;   // x = 6
x %= 4;   // x = 2

Increment and Decrement Operators

Pre-increment vs Post-increment

Operator Name Description
++x Pre-increment Increment first, then use value
x++ Post-increment Use value first, then increment
--x Pre-decrement Decrement first, then use value
x-- Post-decrement Use value first, then decrement
#include <iostream>
using namespace std;

int main() {
    int a = 5, b = 5;

    cout << "Pre-increment: " << ++a << endl;   // Output: 6, a is now 6
    cout << "Post-increment: " << b++ << endl;  // Output: 5, b is now 6

    int x = 10, y = 10;

    cout << "Pre-decrement: " << --x << endl;   // Output: 9, x is now 9
    cout << "Post-decrement: " << y-- << endl;  // Output: 10, y is now 9

    return 0;
}

In Expressions

int a = 5;
int b = ++a + 10;   // a becomes 6, then b = 6 + 10 = 16

int x = 5;
int y = x++ + 10;   // y = 5 + 10 = 15, then x becomes 6

In Loops

// Both achieve the same result in simple loops
for (int i = 0; i < 10; ++i) { }  // Pre-increment (slightly more efficient for iterators)
for (int i = 0; i < 10; i++) { }  // Post-increment

Ternary Operator

The ternary operator (?:) is a shorthand for simple if-else statements.

Syntax

condition ? expression_if_true : expression_if_false

Examples

int a = 10, b = 20;

// Simple ternary
int max = (a > b) ? a : b;  // max = 20

// In output
cout << "Result: " << ((a > b) ? "a is greater" : "b is greater") << endl;

// Nested ternary (use sparingly!)
int x = 5;
string result = (x > 0) ? "positive" : (x < 0) ? "negative" : "zero";

// Equivalent if-else
int max2;
if (a > b) {
    max2 = a;
} else {
    max2 = b;
}

When to Use

Good use cases:

  • Simple value selection
  • Inline assignments
  • Return statements

Avoid when:

  • Logic is complex
  • Multiple statements needed
  • Nested ternaries become confusing

Comma Operator

The comma operator evaluates multiple expressions and returns the last one.

int a, b, c;

// Multiple declarations
int x = 1, y = 2, z = 3;

// In expressions (returns last value)
int result = (a = 5, b = 10, a + b);  // result = 15

// In for loops
for (int i = 0, j = 10; i < j; ++i, --j) {
    cout << i << " " << j << endl;
}

sizeof Operator

The sizeof operator returns the size in bytes of a type or variable.

#include <iostream>
using namespace std;

int main() {
    // Size of types
    cout << "char: " << sizeof(char) << " bytes" << endl;        // 1
    cout << "int: " << sizeof(int) << " bytes" << endl;          // 4 (typically)
    cout << "double: " << sizeof(double) << " bytes" << endl;    // 8
    cout << "long long: " << sizeof(long long) << " bytes" << endl;  // 8

    // Size of variables
    int arr[10];
    cout << "Array of 10 ints: " << sizeof(arr) << " bytes" << endl;  // 40
    cout << "Number of elements: " << sizeof(arr)/sizeof(arr[0]) << endl;  // 10

    // Size of expressions
    cout << "sizeof(5 + 3.14): " << sizeof(5 + 3.14) << " bytes" << endl;  // 8 (double)

    return 0;
}

Operator Precedence

Operators are evaluated based on their precedence (priority) and associativity.

Precedence Table (Highest to Lowest)

Priority Operators Associativity
1 :: Left to right
2 () [] -> . ++ -- (postfix) Left to right
3 ++ -- (prefix) + - (unary) ! ~ * & sizeof Right to left
4 * / % Left to right
5 + - Left to right
6 << >> Left to right
7 < <= > >= Left to right
8 == != Left to right
9 & Left to right
10 ^ Left to right
11 \| Left to right
12 && Left to right
13 \|\| Left to right
14 ?: Right to left
15 = += -= *= /= etc. Right to left
16 , Left to right

Examples

int result;

// Precedence affects evaluation order
result = 2 + 3 * 4;        // 14 (not 20), * before +
result = (2 + 3) * 4;      // 20, parentheses override

// Multiple operators
result = 10 - 5 - 2;       // 3, left to right
result = 2 * 3 + 4 / 2;    // 6 + 2 = 8

// Assignment is right-to-left
int a, b, c;
a = b = c = 10;            // c=10, b=c, a=b

// Logical operators
bool x = true || false && false;  // true (&& before ||)
bool y = (true || false) && false; // false

Best Practice: Use parentheses to make precedence explicit and code more readable.


Type Casting Operators

C-Style Casting

int a = 10;
double b = (double)a;       // C-style cast
double c = double(a);       // Function-style cast

C++ Casting Operators

static_cast

For well-defined type conversions:

double d = 3.14;
int i = static_cast<int>(d);  // i = 3

// Pointer conversion in class hierarchy
Derived* dp = new Derived();
Base* bp = static_cast<Base*>(dp);

dynamic_cast

For safe downcasting with polymorphism:

Base* bp = new Derived();
Derived* dp = dynamic_cast<Derived*>(bp);
if (dp != nullptr) {
    // Safe to use dp
}

const_cast

For adding/removing const qualifier:

const int* cp = &a;
int* p = const_cast<int*>(cp);  // Remove const (use carefully!)

reinterpret_cast

For low-level bit reinterpretation:

int* ip = new int(65);
char* cp = reinterpret_cast<char*>(ip);  // Dangerous!

Common Mistakes

1. Assignment vs Comparison

// WRONG: Assignment in condition
if (x = 5) { }  // Always true, assigns 5 to x

// CORRECT: Comparison
if (x == 5) { }  // Compares x with 5

2. Integer Division

// WRONG: Expects decimal result
double result = 5 / 2;  // result = 2.0

// CORRECT: Use float operand
double result = 5.0 / 2;  // result = 2.5

3. Operator Precedence

// WRONG: Unexpected result
if (a & b == 0) { }  // Parsed as: a & (b == 0)

// CORRECT: Use parentheses
if ((a & b) == 0) { }

4. Increment in Complex Expressions

// UNDEFINED BEHAVIOR
int i = 1;
int j = i++ + ++i;  // Result is undefined!

// CORRECT: Separate statements
int i = 1;
int temp = i++;
int j = temp + ++i;

5. Floating-Point Comparison

// WRONG: Direct comparison
if (0.1 + 0.2 == 0.3) { }  // May be false!

// CORRECT: Use epsilon
if (fabs((0.1 + 0.2) - 0.3) < 1e-9) { }

Recommended Conventions

  1. Use parentheses for clarity

cpp result = (a * b) + (c / d); // Clear precedence

  1. Prefer prefix increment for non-primitive types

cpp for (auto it = vec.begin(); it != vec.end(); ++it) // More efficient

  1. Avoid complex expressions

```cpp // Bad x = a++ + ++b * c-- / ++d;

// Good: Break into multiple statements ++b; x = a + b * c / d; --c; ++d; ++a; ```

  1. Use compound assignment when possible

cpp x += 5; // Cleaner than x = x + 5

  1. Be careful with signed/unsigned operations cpp unsigned int u = 10; int s = -5; // u + s may give unexpected results due to implicit conversion

Summary

Category Key Points
Arithmetic +, -, *, /, %; Integer division truncates
Relational Return bool; Use epsilon for float comparison
Logical Short-circuit evaluation; &&, \|\|, !
Bitwise Work on bits; Useful for flags and optimization
Assignment = and compound operators (+=, -=, etc.)
Increment/Decrement Pre vs Post affects when value changes
Ternary ?: for simple conditionals
Precedence Use parentheses when in doubt
Casting Prefer C++ casts over C-style casts

Master operators to write efficient and correct C++ expressions!