C++ Operators and Expressions: Types, Precedence, Overloading & Best Practices
1. Operators and Expressions
Q: What are operators in C++?
Operators are symbols that perform operations on variables and values (operands). An expression is a combination of operands and operators that evaluates to a value. Operators are essential for manipulating data in DSA (e.g., comparisons in sorting, arithmetic in graph algorithms).
Q: What are the main categories of operators in C++?
- Arithmetic:
+,-,*,/,%(addition, subtraction, multiplication, division, modulo). - Relational:
==,!=,<,>,<=,>=(equality, inequality, comparisons). - Logical:
&&(and),||(or),!(not). - Bitwise:
&(and),|(or),^(xor),~(not),<<(left shift),>>(right shift). - Assignment:
=,+=,-=,*=,/=,%=,&=,|=,^=,<<=,>>=. - Increment/Decrement:
++,--(pre- and post-increment/decrement). - Other:
sizeof,typeid,::(scope resolution),new,delete,,(comma),.*,->*(member access).
Q: What is the precedence and associativity of operators?
- Precedence: Determines the order of evaluation (e.g.,
*and/have higher precedence than+and-). - Associativity: Determines the order when operators have the same precedence (e.g., left-to-right for
+,-; right-to-left for=). - Example: In
a + b * c,b * cis evaluated first due to higher precedence of*. - Use parentheses () to override precedence: (e.g.,
(a + b) * c).
Q: Can you give an example of operators and expressions in C++?
#include <iostream>
using namespace std;
int main() {
int a = 10, b = 3;
double c = 2.5;
// Arithmetic operators
cout << "Arithmetic: " << endl;
cout << "a + b = " << a + b << endl; // 13
cout << "a - b = " << a - b << endl; // 7
cout << "a * b = " << a * b << endl; // 30
cout << "a / b = " << a / b << endl; // 3 (integer division)
cout << "a % b = " << a % b << endl; // 1
cout << "a + c = " << a + c << endl; // 12.5
// Relational operators
cout << "\nRelational: " << endl;
cout << boolalpha;
cout << "a == b: " << (a == b) << endl; // false
cout << "a != b: " << (a != b) << endl; // true
cout << "a > b: " << (a > b) << endl; // true
// Logical operators
bool x = true, y = false;
cout << "\nLogical: " << endl;
cout << "x && y: " << (x && y) << endl; // false
cout << "x || y: " << (x || y) << endl; // true
cout << "!x: " << (!x) << endl; // false
// Bitwise operators
cout << "\nBitwise: " << endl;
cout << noboolalpha;
cout << "a & b: " << (a & b) << endl; // 2 (1010 & 0011 = 0010)
cout << "a | b: " << (a | b) << endl; // 11 (1010 | 0011 = 1011)
// Increment/Decrement
cout << "\nIncrement/Decrement: " << endl;
cout << "a++: " << a++ << endl; // 10 (post-increment, prints 10, a becomes 11)
cout << "++a: " << ++a << endl; // 12 (pre-increment)
return 0;
}
Compilation and Execution:
g++ operators_expressions.cpp -o operators_expressions
./operators_expressions
Output:
Arithmetic:
a + b = 13
a - b = 7
a * b = 30
a / b = 3
a % b = 1
a + c = 12.5
Relational:
a == b: false
a != b: true
a > b: true
Logical:
x && y: false
x || y: true
!x: false
Bitwise:
a & b: 2
a | b: 11
Increment/Decrement:
a++: 10
++a: 12
Q: What are the differences between C++ and C operators?
C++ Enhancements:
- C++ supports operator overloading (custom behavior for operators with user-defined types).
- C++ has additional operators like
::(scope resolution),.*,->*(member access), andtypeid. - C++’s
booltype makes logical expressions clearer than C’s integer-based booleans.
Commonality: Most arithmetic, relational, logical, and bitwise operators are identical in C and C++.
Q: What are common mistakes with operators and expressions in C++?
- Precedence Errors: Misunderstanding operator precedence (e.g.,
a + b * cevaluatesb * cfirst). - Integer Division: Forgetting that
int / intyields an integer (e.g.,5 / 2 = 2, not 2.5). - Undefined Behavior: Using post-increment incorrectly (e.g.,
a = a++is undefined). - Type Mismatches: Mixing signed and unsigned types in expressions (e.g.,
unsigned intwithint). - Logical Errors: Confusing
&(bitwise) with&&(logical) or=(assignment) with==(equality).
Q: How are operators used in DSA?
- Arithmetic: Compute distances, weights, or indices (e.g., in graph algorithms).
- Relational: Comparisons in sorting or searching (e.g.,
a < bin quicksort). - Logical: Conditions in algorithms (e.g.,
if (found || visited)in DFS). - Bitwise: Optimize operations (e.g.,
x & 1to check if a number is odd). - Increment/Decrement: Loop counters or array indexing in algorithms.
Q: What is operator overloading in C++?
Operator overloading allows defining custom behavior for operators (e.g., +, ==) for user-defined types like classes or structs.
Example:
#include <iostream>
using namespace std;
class Point {
public:
int x, y;
Point(int x = 0, int y = 0) : x(x), y(y) {}
// Overload + operator
Point operator+(const Point& other) {
return Point(x + other.x, y + other.y);
}
};
int main() {
Point p1(1, 2), p2(3, 4);
Point p3 = p1 + p2; // Calls operator+
cout << "Result: (" << p3.x << ", " << p3.y << ")" << endl; // Output: (4, 6)
return 0;
}
Q: What are short-circuit evaluations in logical expressions?
In && and ||, C++ evaluates only as much as needed:
- For
a && b, ifaisfalse,bis not evaluated. - For
a || b, ifaistrue,bis not evaluated. - This optimizes performance and prevents errors (e.g., checking
ptr != nullptr && *ptr > 0).