30% complete
Operators in C++
Operators are special symbols that perform operations on one or more operands and produce a result. C++ provides a rich set of operators for various types of operations, including arithmetic, logical, bitwise, and more. Understanding operators is essential for effective C++ programming.
Key Takeaways
- C++ provides various types of operators for different operations
- Operators have precedence and associativity rules that determine evaluation order
- C++ allows operator overloading, enabling custom behavior for user-defined types
- Understanding proper operator usage helps prevent common programming errors
- Operators can be unary (one operand), binary (two operands), or ternary (three operands)
Types of Operators in C++
C++ provides a wide range of operators categorized into different types:
- Arithmetic Operators: Perform mathematical calculations
- Relational Operators: Compare values
- Logical Operators: Perform logical operations
- Bitwise Operators: Manipulate individual bits
- Assignment Operators: Assign values to variables
- Increment/Decrement Operators: Increase or decrease values
- Member and Pointer Operators: Access class members and pointers
- Other Operators: Special purpose operators like conditional, sizeof, etc.
Arithmetic Operators
Arithmetic operators perform mathematical operations on numeric operands.
Operator | Name | Example | Result |
---|---|---|---|
+ | Addition | a + b | Sum of a and b |
- | Subtraction | a - b | Difference of a and b |
* | Multiplication | a * b | Product of a and b |
/ | Division | a / b | Quotient of a divided by b |
% | Modulus | a % b | Remainder of a divided by b |
+a | Unary Plus | +a | Value of a (rarely used) |
-a | Unary Minus | -a | Negated value of a |
1#include <iostream>23int main() {4 int a = 10, b = 3;56 std::cout << "a = " << a << ", b = " << b << std::endl;7 std::cout << "a + b = " << a + b << std::endl; // 138 std::cout << "a - b = " << a - b << std::endl; // 79 std::cout << "a * b = " << a * b << std::endl; // 3010 std::cout << "a / b = " << a / b << std::endl; // 3 (integer division)11 std::cout << "a % b = " << a % b << std::endl; // 1 (remainder)1213 // Floating-point division14 double c = 10.0, d = 3.0;15 std::cout << "c / d = " << c / d << std::endl; // 3.33333...1617 // Unary operators18 int e = 5;19 std::cout << "+e = " << +e << std::endl; // 520 std::cout << "-e = " << -e << std::endl; // -52122 return 0;23}
Division Behavior
When dividing two integers in C++, the result will be an integer (truncated division). If you want floating-point division, at least one operand must be a floating-point number. The modulus operator %
works only with integer operands.
Relational Operators
Relational operators compare two values and return a boolean result (true or false). These operators are often used in conditional statements.
Operator | Name | Example | Result |
---|---|---|---|
== | Equal to | a == b | True if a equals b |
!= | Not equal to | a != b | True if a is not equal to b |
> | Greater than | a > b | True if a is greater than b |
< | Less than | a < b | True if a is less than b |
>= | Greater than or equal to | a >= b | True if a is greater than or equal to b |
<= | Less than or equal to | a <= b | True if a is less than or equal to b |
1#include <iostream>23int main() {4 int a = 10, b = 20, c = 10;56 std::cout << std::boolalpha; // Print true/false instead of 1/078 std::cout << "a = " << a << ", b = " << b << ", c = " << c << std::endl;9 std::cout << "a == b: " << (a == b) << std::endl; // false10 std::cout << "a == c: " << (a == c) << std::endl; // true11 std::cout << "a != b: " << (a != b) << std::endl; // true12 std::cout << "a > b: " << (a > b) << std::endl; // false13 std::cout << "a < b: " << (a < b) << std::endl; // true14 std::cout << "a >= c: " << (a >= c) << std::endl; // true15 std::cout << "a <= c: " << (a <= c) << std::endl; // true1617 return 0;18}
Common Mistake:
Don't confuse the equality operator (==
) with the assignment operator (=
). The equality operator compares two values, while the assignment operator assigns a value to a variable. Using =
in a condition will assign a value and then evaluate it as a boolean.
Logical Operators
Logical operators are used to combine multiple conditions or to negate a condition. They operate on boolean values and return boolean results.
Operator | Name | Example | Result |
---|---|---|---|
&& | Logical AND | a && b | True if both a and b are true |
|| | Logical OR | a || b | True if either a or b is true |
! | Logical NOT | !a | True if a is false, false if a is true |
1#include <iostream>23int main() {4 bool a = true, b = false;56 std::cout << std::boolalpha; // Print true/false instead of 1/078 std::cout << "a = " << a << ", b = " << b << std::endl;9 std::cout << "a && b: " << (a && b) << std::endl; // false10 std::cout << "a || b: " << (a || b) << std::endl; // true11 std::cout << "!a: " << (!a) << std::endl; // false12 std::cout << "!b: " << (!b) << std::endl; // true1314 // Combining logical operators15 std::cout << "!(a && b): " << (!(a && b)) << std::endl; // true16 std::cout << "!a || !b: " << (!a || !b) << std::endl; // true (De Morgan's Law)1718 // Short-circuit evaluation19 int x = 5, y = 0;2021 // The second condition is not evaluated if the first is false (AND)22 if (y != 0 && x / y > 2) {23 std::cout << "x / y > 2" << std::endl;24 } else {25 std::cout << "Condition not met or division by zero avoided" << std::endl;26 }2728 // The second condition is not evaluated if the first is true (OR)29 if (y == 0 || x / y > 2) {30 std::cout << "Either y is zero or x / y > 2" << std::endl;31 }3233 return 0;34}
Short-Circuit Evaluation
C++ uses short-circuit evaluation for logical operators:
- For
&&
, if the first operand is false, the second operand is not evaluated because the result will always be false. - For
||
, if the first operand is true, the second operand is not evaluated because the result will always be true.
Bitwise Operators
Bitwise operators manipulate individual bits of integer values. They are useful for low-level programming, optimization, and working with hardware interfaces.
Operator | Name | Example | Result |
---|---|---|---|
& | Bitwise AND | a & b | 1 if both bits are 1, otherwise 0 |
| | Bitwise OR | a | b | 1 if either bit is 1, otherwise 0 |
^ | Bitwise XOR | a ^ b | 1 if bits are different, otherwise 0 |
~ | Bitwise NOT | ~a | Inverts all bits (0 becomes 1, 1 becomes 0) |
<< | Left shift | a << b | Shifts bits of a left by b positions |
>> | Right shift | a >> b | Shifts bits of a right by b positions |
1#include <iostream>2#include <bitset>34int main() {5 unsigned char a = 5; // 00000101 in binary6 unsigned char b = 3; // 00000011 in binary78 std::cout << "a = " << static_cast<int>(a) << " (" << std::bitset<8>(a) << ")" << std::endl;9 std::cout << "b = " << static_cast<int>(b) << " (" << std::bitset<8>(b) << ")" << std::endl;1011 // Bitwise AND12 std::cout << "a & b = " << static_cast<int>(a & b)13 << " (" << std::bitset<8>(a & b) << ")" << std::endl;1415 // Bitwise OR16 std::cout << "a | b = " << static_cast<int>(a | b)17 << " (" << std::bitset<8>(a | b) << ")" << std::endl;1819 // Bitwise XOR20 std::cout << "a ^ b = " << static_cast<int>(a ^ b)21 << " (" << std::bitset<8>(a ^ b) << ")" << std::endl;2223 // Bitwise NOT24 std::cout << "~a = " << static_cast<int>(~a)25 << " (" << std::bitset<8>(~a) << ")" << std::endl;2627 // Left shift28 std::cout << "a << 1 = " << static_cast<int>(a << 1)29 << " (" << std::bitset<8>(a << 1) << ")" << std::endl;3031 // Right shift32 std::cout << "a >> 1 = " << static_cast<int>(a >> 1)33 << " (" << std::bitset<8>(a >> 1) << ")" << std::endl;3435 return 0;36}
Common Bitwise Operations
- Setting a bit:
x |= (1 << n)
- Sets the nth bit to 1 - Clearing a bit:
x &= ~(1 << n)
- Sets the nth bit to 0 - Toggling a bit:
x ^= (1 << n)
- Flips the nth bit - Checking a bit:
(x & (1 << n)) != 0
- Checks if the nth bit is set - Multiplication by 2n:
x << n
- Equivalent to x * 2^n - Division by 2n:
x >> n
- Equivalent to x / 2^n
Assignment Operators
Assignment operators are used to assign values to variables. C++ provides shorthand operators that combine assignment with other operations.
Operator | Name | Example | Equivalent to |
---|---|---|---|
= | Assignment | a = b | a = b |
+= | Addition assignment | a += b | a = a + b |
-= | Subtraction assignment | a -= b | a = a - b |
*= | Multiplication assignment | a *= b | a = a * b |
/= | Division assignment | a /= b | a = a / b |
%= | Modulus assignment | a %= b | a = a % b |
&= | Bitwise AND assignment | a &= b | a = a & b |
|= | Bitwise OR assignment | a |= b | a = a | b |
^= | Bitwise XOR assignment | a ^= b | a = a ^ b |
<<= | Left shift assignment | a <<= b | a = a << b |
>>= | Right shift assignment | a >>= b | a = a >> b |
1#include <iostream>23int main() {4 int a = 10;56 std::cout << "Initial value: a = " << a << std::endl;78 // Addition assignment9 a += 5; // Equivalent to a = a + 510 std::cout << "After a += 5: a = " << a << std::endl;1112 // Subtraction assignment13 a -= 3; // Equivalent to a = a - 314 std::cout << "After a -= 3: a = " << a << std::endl;1516 // Multiplication assignment17 a *= 2; // Equivalent to a = a * 218 std::cout << "After a *= 2: a = " << a << std::endl;1920 // Division assignment21 a /= 4; // Equivalent to a = a / 422 std::cout << "After a /= 4: a = " << a << std::endl;2324 // Modulus assignment25 a %= 2; // Equivalent to a = a % 226 std::cout << "After a %= 2: a = " << a << std::endl;2728 // Bitwise assignments29 a = 10; // Reset to 10 (1010 in binary)30 std::cout << "Reset to: a = " << a << std::endl;3132 a &= 12; // 10 & 12 = 1010 & 1100 = 1000 = 833 std::cout << "After a &= 12: a = " << a << std::endl;3435 a |= 5; // 8 | 5 = 1000 | 0101 = 1101 = 1336 std::cout << "After a |= 5: a = " << a << std::endl;3738 a ^= 9; // 13 ^ 9 = 1101 ^ 1001 = 0100 = 439 std::cout << "After a ^= 9: a = " << a << std::endl;4041 a <<= 1; // 4 << 1 = 0100 << 1 = 1000 = 842 std::cout << "After a <<= 1: a = " << a << std::endl;4344 a >>= 2; // 8 >> 2 = 1000 >> 2 = 0010 = 245 std::cout << "After a >>= 2: a = " << a << std::endl;4647 return 0;48}
Increment and Decrement Operators
Increment and decrement operators are unary operators that increase or decrease the value of a variable by one. They can be used in prefix or postfix form.
Operator | Name | Description |
---|---|---|
++a | Pre-increment | Increments a by 1, then returns a |
a++ | Post-increment | Returns a, then increments a by 1 |
--a | Pre-decrement | Decrements a by 1, then returns a |
a-- | Post-decrement | Returns a, then decrements a by 1 |
1#include <iostream>23int main() {4 int a = 5, b = 5, c = 5, d = 5;5 int result;67 // Pre-increment8 result = ++a; // a is incremented to 6, then assigned to result9 std::cout << "After ++a: a = " << a << ", result = " << result << std::endl;1011 // Post-increment12 result = b++; // b (5) is assigned to result, then b is incremented to 613 std::cout << "After b++: b = " << b << ", result = " << result << std::endl;1415 // Pre-decrement16 result = --c; // c is decremented to 4, then assigned to result17 std::cout << "After --c: c = " << c << ", result = " << result << std::endl;1819 // Post-decrement20 result = d--; // d (5) is assigned to result, then d is decremented to 421 std::cout << "After d--: d = " << d << ", result = " << result << std::endl;2223 // Common usage in loops24 std::cout << "\nCounting up:" << std::endl;25 for (int i = 1; i <= 3; ++i) { // Pre-increment is generally preferred in loops26 std::cout << i << " ";27 }2829 std::cout << "\nCounting down:" << std::endl;30 for (int i = 3; i > 0; --i) { // Pre-decrement is generally preferred in loops31 std::cout << i << " ";32 }3334 return 0;35}
Pre vs Post Increment/Decrement:
Though the difference between prefix and postfix forms might seem subtle, it can significantly impact your code:
- For basic data types, performance is usually the same
- For custom objects, the postfix form creates a temporary copy, making it potentially less efficient
- When the result is not used, there's no difference in behavior
- Prefer prefix form (++i) in loops for potential optimization
Other Operators
C++ provides several other important operators for various purposes.
Operator | Name | Description |
---|---|---|
? : | Conditional (Ternary) | Evaluates a condition and returns one of two values |
sizeof | Size-of | Returns the size of a variable or type in bytes |
, | Comma | Evaluates multiple expressions and returns the last one |
. | Member access | Accesses members of an object |
-> | Pointer-to-member | Accesses members of an object through a pointer |
:: | Scope resolution | Accesses namespace, class, or enumeration members |
.* , ->* | Pointer to member | Access member using pointer to member |
typeid | Type identification | Returns the type identification |
new , delete | Dynamic memory | Allocates and deallocates memory |
1#include <iostream>2#include <string>3#include <typeinfo>45class Person {6public:7 std::string name;8 int age;910 Person(const std::string& n, int a) : name(n), age(a) {}1112 void display() const {13 std::cout << "Name: " << name << ", Age: " << age << std::endl;14 }15};1617int main() {18 // Conditional (ternary) operator19 int x = 10, y = 20;20 int max = (x > y) ? x : y; // If x > y, max = x, otherwise max = y21 std::cout << "Max value: " << max << std::endl;2223 // sizeof operator24 std::cout << "Size of int: " << sizeof(int) << " bytes" << std::endl;25 std::cout << "Size of x: " << sizeof x << " bytes" << std::endl;2627 // Comma operator28 int a, b;29 a = (b = 3, b + 2); // b is assigned 3, then a is assigned b + 2 (5)30 std::cout << "a = " << a << ", b = " << b << std::endl;3132 // Member access operators33 Person person("Alice", 30);34 Person* personPtr = &person;3536 // . operator for objects37 person.display();38 std::cout << "Using . operator: " << person.name << std::endl;3940 // -> operator for pointers to objects41 personPtr->display();42 std::cout << "Using -> operator: " << personPtr->name << std::endl;4344 // :: scope resolution operator45 std::cout << "Using :: operator: " << std::endl;46 std::cout << std::boolalpha; // std:: is using the scope resolution operator4748 // typeid operator49 std::cout << "Type of x: " << typeid(x).name() << std::endl;50 std::cout << "Type of person: " << typeid(person).name() << std::endl;5152 // new and delete operators53 int* dynamicInt = new int(42);54 std::cout << "Value of dynamicInt: " << *dynamicInt << std::endl;55 delete dynamicInt; // Free the allocated memory5657 // Array allocation58 int* array = new int[5]{1, 2, 3, 4, 5};59 std::cout << "Array values: ";60 for (int i = 0; i < 5; i++) {61 std::cout << array[i] << " ";62 }63 std::cout << std::endl;64 delete[] array; // Free the array memory6566 return 0;67}
Operator Overloading
One of the powerful features of C++ is the ability to overload operators for user-defined types. This allows custom classes to use standard operators like +, -, *, etc., with custom behavior.
1#include <iostream>23class Complex {4private:5 double real;6 double imag;78public:9 // Constructor10 Complex(double r = 0.0, double i = 0.0) : real(r), imag(i) {}1112 // Overload + operator13 Complex operator+(const Complex& other) const {14 return Complex(real + other.real, imag + other.imag);15 }1617 // Overload - operator18 Complex operator-(const Complex& other) const {19 return Complex(real - other.real, imag - other.imag);20 }2122 // Overload * operator23 Complex operator*(const Complex& other) const {24 return Complex(25 real * other.real - imag * other.imag,26 real * other.imag + imag * other.real27 );28 }2930 // Overload == operator31 bool operator==(const Complex& other) const {32 return (real == other.real) && (imag == other.imag);33 }3435 // Overload != operator36 bool operator!=(const Complex& other) const {37 return !(*this == other);38 }3940 // Overload unary - operator41 Complex operator-() const {42 return Complex(-real, -imag);43 }4445 // Overload prefix increment operator46 Complex& operator++() {47 ++real;48 return *this;49 }5051 // Overload postfix increment operator52 Complex operator++(int) {53 Complex temp = *this;54 ++real;55 return temp;56 }5758 // Display the complex number59 void display() const {60 std::cout << real;61 if (imag >= 0) {62 std::cout << " + " << imag << "i";63 } else {64 std::cout << " - " << -imag << "i";65 }66 }6768 // Friend function to overload << operator69 friend std::ostream& operator<<(std::ostream& os, const Complex& c);70};7172// Overload the << operator for Complex using a friend function73std::ostream& operator<<(std::ostream& os, const Complex& c) {74 os << c.real;75 if (c.imag >= 0) {76 os << " + " << c.imag << "i";77 } else {78 os << " - " << -c.imag << "i";79 }80 return os;81}8283int main() {84 Complex c1(3, 4);85 Complex c2(1, -2);8687 std::cout << "c1 = " << c1 << std::endl;88 std::cout << "c2 = " << c2 << std::endl;8990 // Using overloaded operators91 Complex sum = c1 + c2;92 Complex diff = c1 - c2;93 Complex prod = c1 * c2;9495 std::cout << "c1 + c2 = " << sum << std::endl;96 std::cout << "c1 - c2 = " << diff << std::endl;97 std::cout << "c1 * c2 = " << prod << std::endl;9899 // Using comparison operators100 std::cout << "c1 == c2: " << (c1 == c2) << std::endl;101 std::cout << "c1 != c2: " << (c1 != c2) << std::endl;102103 // Using unary operator104 Complex neg = -c1;105 std::cout << "-c1 = " << neg << std::endl;106107 // Using increment operators108 Complex c3 = c1;109 std::cout << "Original c3 = " << c3 << std::endl;110 std::cout << "++c3 = " << ++c3 << std::endl;111 std::cout << "c3 after prefix increment = " << c3 << std::endl;112113 std::cout << "c3++ = " << c3++ << std::endl;114 std::cout << "c3 after postfix increment = " << c3 << std::endl;115116 return 0;117}
Operator Overloading Guidelines
- Maintain the original semantics of operators when overloading (e.g., + should be used for addition-like operations)
- Use member functions for operators that modify the left operand (e.g., +=, -=)
- Use non-member functions for operators where the left operand might be converted (e.g., allowing int + MyClass)
- Consider overloading related operators together (e.g., if you overload ==, also overload !=)
- Make sure to handle self-assignment in assignment operators
Operator Precedence and Associativity
When an expression contains multiple operators, operator precedence and associativity determine the order of evaluation. Operators with higher precedence are evaluated first. Associativity determines the order of evaluation for operators with the same precedence.
Operator Precedence (Highest to Lowest)
- Scope resolution
::
- Member access
. ->
, Post-increment/decrement++ --
, Namestypeid
, Casting - Pre-increment/decrement
++ --
, Unary+ - ! ~
, Sizesizeof
, Memorynew delete
- Pointer-to-member
.* ->*
- Multiplicative
* / %
- Additive
+ -
- Shift
<< >>
- Relational
< <= > >=
- Equality
== !=
- Bitwise AND
&
- Bitwise XOR
^
- Bitwise OR
|
- Logical AND
&&
- Logical OR
||
- Conditional
?:
- Assignment
= += -= *= /= %= &= ^= |= <<= >>=
- Comma
,
1#include <iostream>23int main() {4 int a = 5, b = 3, c = 10;5 int result;67 // Example 1: Precedence of arithmetic operators8 result = a + b * c; // * has higher precedence than +9 std::cout << "a + b * c = " << result << std::endl; // 5 + (3 * 10) = 351011 // Using parentheses to override precedence12 result = (a + b) * c;13 std::cout << "(a + b) * c = " << result << std::endl; // (5 + 3) * 10 = 801415 // Example 2: Precedence of logical operators16 bool test = a > b && c > a; // && has lower precedence than >17 std::cout << "a > b && c > a = " << std::boolalpha << test << std::endl; // (5 > 3) && (10 > 5) = true1819 // Example 3: Assignment vs. equality20 bool equal = (a = b) == c; // = has lower precedence than ==21 std::cout << "After a = b, a = " << a << std::endl; // a is now 322 std::cout << "(a = b) == c = " << equal << std::endl; // (3) == 10 = false2324 // Reset a25 a = 5;2627 // Example 4: Associativity28 // Left-to-right associativity of *29 result = a * b * c; // (a * b) * c30 std::cout << "a * b * c = " << result << std::endl; // (5 * 3) * 10 = 1503132 // Right-to-left associativity of =33 a = b = c; // a = (b = c)34 std::cout << "After a = b = c: a = " << a << ", b = " << b << ", c = " << c << std::endl;3536 return 0;37}
Best Practice:
When in doubt about operator precedence, use parentheses to make your intention explicit. This improves code readability and prevents unexpected behavior due to misunderstood precedence rules.
Summary
C++ provides a comprehensive set of operators for various operations. Understanding these operators and their behavior is essential for effective C++ programming.
- Arithmetic operators perform mathematical calculations
- Relational operators compare values
- Logical operators combine conditions
- Bitwise operators manipulate individual bits
- Assignment operators assign values to variables
- Increment/decrement operators increase or decrease values by one
- Other operators like conditional, sizeof, and member access operators serve specific purposes
- Operator overloading allows custom behavior for user-defined types
- Operator precedence and associativity determine the order of evaluation
Mastering these operators will allow you to write more concise, efficient, and readable C++ code. Remember to use parentheses when in doubt about operator precedence and to consider the semantics of operators when overloading them for custom types.
Related Tutorials
Learn about variables and data types in C++.
Learn moreUnderstand control flow statements in C++.
Learn moreLearn how to define and use functions in C++.
Learn more