Operators
Operators and Expressions
Section titled “Operators and Expressions”Operators are symbols that perform operations on operands (values, variables, or expressions). Understanding operators is essential for writing effective C++ code. This chapter covers all the operators in C++ and demonstrates how to use them effectively.
Operator Overview
Section titled “Operator Overview”C++ provides a rich set of operators organized into several categories:
┌─────────────────────────────────────────────────────────────┐│ C++ Operators │├─────────────────────────────────────────────────────────────┤│ Arithmetic → + - * / % ++ -- ││ Comparison → == != < > <= >= ││ Logical → && || ! ││ Bitwise → & | ^ ~ << >> ││ Assignment → = += -= *= /= %= <<= >>= &= |= ││ Ternary → ?: ││ Member Access → . -> [] () ││ Type Cast → static_cast dynamic_cast etc. ││ Other → sizeof , (type) new delete │└─────────────────────────────────────────────────────────────┘Arithmetic Operators
Section titled “Arithmetic Operators”These operators perform mathematical calculations.
Basic Arithmetic
Section titled “Basic Arithmetic”int a = 10, b = 3;
int sum = a + b; // 13int diff = a - b; // 7int prod = a * b; // 30int quot = a / b; // 3 (integer division)int rem = a % b; // 1 (remainder)Division Behavior
Section titled “Division Behavior”// Integer division (truncates toward zero)int x = 7 / 2; // 3int y = -7 / 2; // -3
// Floating-point divisiondouble d1 = 7.0 / 2; // 3.5double d2 = 7 / 2.0; // 3.5double d3 = 7.0 / 2.0; // 3.5Increment and Decrement
Section titled “Increment and Decrement”int x = 5;
// Prefix (increment, then use)int a = ++x; // x becomes 6, a is 6
// Postfix (use, then increment)int y = 5;int b = y++; // b is 5, y becomes 6
// Same with decrementint z = 5;--z; // z is 4z--; // z becomes 3Common Pitfall:
// Avoid in production code (confusing)int i = 0;std::cout << i++ << std::endl; // Prints 0, then i becomes 1
// Prefer:int i = 0;std::cout << i << std::endl;i++;Assignment Operators
Section titled “Assignment Operators”Assignment operators assign values to variables.
Simple Assignment
Section titled “Simple Assignment”int x = 10; // Basic assignmentx = 20; // Change valueCompound Assignment
Section titled “Compound Assignment”These operators combine an operation with assignment:
int x = 10;
x += 5; // x = x + 5 → x is 15x -= 5; // x = x - 5 → x is 10x *= 2; // x = x * 2 → x is 20x /= 4; // x = x / 4 → x is 5x %= 3; // x = x % 3 → x is 2
x <<= 2; // x = x << 2 (bitwise left shift)x >>= 1; // x = x >> 1 (bitwise right shift)x &= 0xF; // x = x & 0xF (bitwise AND)x |= 0xF; // x = x | 0xF (bitwise OR)x ^= 0xF; // x = x ^ 0xF (bitwise XOR)Comparison (Relational) Operators
Section titled “Comparison (Relational) Operators”These operators compare two values and return a boolean result.
int a = 10, b = 20;
bool equal = (a == b); // falsebool notEqual = (a != b); // truebool less = (a < b); // truebool greater = (a > b); // falsebool lessEq = (a <= b); // truebool greaterEq = (a >= b); // falseImportant: Don’t confuse = (assignment) with == (comparison)!
// Common bugif (x = 5) { // OOPS! Assigns 5 to x, always true // This always executes}
// Correctif (x == 5) { // This executes only if x equals 5}Logical Operators
Section titled “Logical Operators”Logical operators combine boolean expressions.
bool a = true, b = false;
bool andResult = a && b; // false (both must be true)bool orResult = a || b; // true (at least one is true)bool notResult = !a; // false (negation)bool notResult2 = !b; // trueShort-Circuit Evaluation
Section titled “Short-Circuit Evaluation”C++ evaluates expressions lazily:
// If first is false, second is not evaluated (AND)if (ptr != nullptr && ptr->value > 0) { // Safe: ptr->value only accessed if ptr is not null}
// If first is true, second is not evaluated (OR)if (ptr == nullptr || ptr->value == 0) { // Handles null case}Bitwise Operators
Section titled “Bitwise Operators”Bitwise operators manipulate individual bits in integer types.
| Operator | Name | Description |
|---|---|---|
& | AND | 1 if both bits are 1 |
| | OR | 1 if either bit is 1 |
^ | XOR | 1 if bits are different |
~ | NOT | Inverts all bits |
<< | LSHIFT | Shifts bits left |
>> | RSHIFT | Shifts bits right |
Bitwise Examples
Section titled “Bitwise Examples”unsigned int x = 5; // Binary: 0101unsigned int y = 3; // Binary: 0011
unsigned int andResult = x & y; // 0001 = 1unsigned int orResult = x | y; // 0111 = 7unsigned int xorResult = x ^ y; // 0110 = 6unsigned int notResult = ~x; // ...11111010 (all bits inverted)
unsigned int leftShift = x << 1; // 1010 = 10 (multiply by 2)unsigned int rightShift = x >> 1; // 0010 = 2 (divide by 2)Practical Bitwise Uses
Section titled “Practical Bitwise Uses”// Check if a bit is setbool bit3Set = (value & (1 << 3)) != 0;
// Set a bitvalue |= (1 << 3);
// Clear a bitvalue &= ~(1 << 3);
// Toggle a bitvalue ^= (1 << 3);
// Check multiple flagsif (options & (FLAG_A | FLAG_B)) { // Either flag is set}Ternary Operator
Section titled “Ternary Operator”The ternary operator ?: is a compact if-else:
// condition ? value_if_true : value_if_false
int age = 20;std::string status = (age >= 18) ? "adult" : "minor";// status is "adult"
// Equivalent if-else:std::string status;if (age >= 18) { status = "adult";} else { status = "minor";}Nested ternary (avoid for readability):
// Hard to readchar grade = (score >= 90) ? 'A' : (score >= 80) ? 'B' : (score >= 70) ? 'C' : (score >= 60) ? 'D' : 'F';Operator Precedence
Section titled “Operator Precedence”Operators have different precedence (priority) levels:
| Precedence | Operators | Associativity |
|---|---|---|
| 1 (highest) | () [] -> . | Left to right |
| 2 | ! ~ ++ -- + - (unary) *(dereference) &(address) sizeof new delete | Right to left |
| 3 | * / % | Left to right |
| 4 | + - (binary) | Left to right |
| 5 | << >> | Left to right |
| 6 | < <= > >= | Left to right |
| 7 | == != | Left to right |
| 8 | & (bitwise AND) | Left to right |
| 9 | ^ | Left to right |
| 10 | | | Left to right |
| 11 | && | Left to right |
| 12 | || | Left to right |
| 13 | ?: | Right to left |
| 14 | = += -= *= /= %= <<= >>= &= |= ^= | Right to left |
| 15 (lowest) | , | Left to right |
Best Practice: Use parentheses to make precedence explicit:
// Clearint result = (a + b) * c;
// Could be confusing without parenthesesint result = a + b * c; // a + (b * c)Comma Operator
Section titled “Comma Operator”The comma operator evaluates expressions left to right and returns the last value:
int a, b;
// In for loops (common use)for (int i = 0, j = 10; i < j; i++, j--) { // i and j are both updated}
// As expression (avoid - reduces readability)int x = (a = 5, b = 10, a + b); // x is 15sizeof Operator
Section titled “sizeof Operator”Returns the size of a type or variable in bytes:
int arr[10];
sizeof(int); // 4 (typically)sizeof(arr); // 40 (entire array)sizeof(arr) / sizeof(arr[0]); // 10 (array length)Member Access Operators
Section titled “Member Access Operators”struct Point { int x; int y;};
Point p{10, 20};
// Direct member accessp.x = 15;
// Pointer member accessPoint* ptr = &p;ptr->x = 25; // Same as (*ptr).x
// Subscript operatorint arr[5] = {1, 2, 3, 4, 5};int first = arr[0];Type Casting Operators
Section titled “Type Casting Operators”Modern C++ provides safer casting operators:
double d = 3.14159;
// static_cast - for well-defined conversionsint i = static_cast<int>(d); // 3
// const_cast - add or remove constconst int ci = 42;int* pi = const_cast<int*>(&ci);
// reinterpret_cast - low-level reinterpretationint* ip = reinterpret_cast<int*>(&d);
// dynamic_cast - for polymorphic typesclass Base { virtual void f() {} };class Derived : public Base {};Base* base = new Derived;Derived* derived = dynamic_cast<Derived*>(base);Expressions
Section titled “Expressions”An expression is a combination of operators and operands that evaluates to a value:
// Simple expressions42 // Literal expressionx // Variable expressionx + y // Arithmetic expressionx > 0 // Relational expressionx && y // Logical expression
// Complex expressionsint result = (x + y) * (a - b) / 2;bool valid = (x >= 0) && (x <= 100) && (ptr != nullptr);
// Expression with side effectsint i = ++x + y--; // Increments x, decrements yOperator Overloading
Section titled “Operator Overloading”You can define custom behavior for operators with user-defined types (covered in OOP section):
class Vector {public: double x, y;
// Overload + operator Vector operator+(const Vector& other) { return {x + other.x, y + other.y}; }};
Vector v1{1, 2}, v2{3, 4};Vector v3 = v1 + v2; // Uses overloaded +Best Practices
Section titled “Best Practices”1. Use Parentheses for Clarity
Section titled “1. Use Parentheses for Clarity”// Unclearint result = a + b * c - d / e;
// Clearint result = ((a + (b * c)) - (d / e));2. Avoid Complex Nested Ternary
Section titled “2. Avoid Complex Nested Ternary”// Avoidstd::string grade = score >= 90 ? "A" : score >= 80 ? "B" : score >= 70 ? "C" : "D";
// Preferif (score >= 90) grade = "A";else if (score >= 80) grade = "B";// etc.3. Use Compound Assignment
Section titled “3. Use Compound Assignment”// Clearx += 5;
// Less clearx = x + 5;4. Be Careful with Bitwise on Signed Types
Section titled “4. Be Careful with Bitwise on Signed Types”// Use unsigned for bitwise operationsunsigned int flags = 0xFF;unsigned int mask = 0x0F;unsigned int result = flags & mask;
// Signed behavior is implementation-definedint signedValue = -1;unsigned int result2 = signedValue >> 1; // Undefined behavior!Complete Example
Section titled “Complete Example”#include <iostream>
int main() { // Arithmetic int a = 10, b = 3; std::cout << "Arithmetic:" << std::endl; std::cout << " a + b = " << (a + b) << std::endl; std::cout << " a - b = " << (a - b) << std::endl; std::cout << " a * b = " << (a * b) << std::endl; std::cout << " a / b = " << (a / b) << std::endl; std::cout << " a % b = " << (a % b) << std::endl;
// Comparison std::cout << "\nComparison:" << std::endl; std::cout << " a == b: " << (a == b) << std::endl; std::cout << " a != b: " << (a != b) << std::endl; std::cout << " a < b: " << (a < b) << std::endl; std::cout << " a > b: " << (a > b) << std::endl;
// Logical bool x = true, y = false; std::cout << "\nLogical:" << std::endl; std::cout << " x && y: " << (x && y) << std::endl; std::cout << " x || y: " << (x || y) << std::endl; std::cout << " !x: " << (!x) << std::endl;
// Bitwise unsigned int m = 5, n = 3; std::cout << "\nBitwise:" << std::endl; std::cout << " m & n: " << (m & n) << std::endl; std::cout << " m | n: " << (m | n) << std::endl; std::cout << " m ^ n: " << (m ^ n) << std::endl; std::cout << " ~m: " << (~m) << std::endl; std::cout << " m << 1: " << (m << 1) << std::endl; std::cout << " m >> 1: " << (m >> 1) << std::endl;
// Ternary int score = 85; std::cout << "\nTernary:" << std::endl; std::cout << " Grade: " << (score >= 60 ? "Pass" : "Fail") << std::endl;
return 0;}Key Takeaways
Section titled “Key Takeaways”- C++ provides arithmetic, comparison, logical, and bitwise operators
- Operator precedence determines the order of evaluation; use parentheses to be clear
- The increment/decrement operators (
++,--) come in prefix and postfix forms - Be careful not to confuse
=(assignment) with==(comparison) - Bitwise operators are powerful for flag manipulation and low-level programming
- Modern C++ prefers
static_castover C-style casts - Keep expressions simple and readable
Next Steps
Section titled “Next Steps”Now let’s learn about control flow statements in C++.
Next Chapter: 06_control_flow.md - Control Flow Statements