You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Operators are symbols that perform operations on variables or values.
They allow concise data manipulation, comparisons, and control of program
logic.
Operators follow specific rules of precedence and associativity to determine
the order of evaluation in complex expressions.
Additionally, operators can be overloaded for custom behavior in
user-defined types, improving code flexibility and reusability.
In fact, it's a function. It makes our code clearer.
Categories
Arithmetic operators:
Perform basic mathematical operations.
+ (Addition).
- (Subtraction).
* (Multiplication).
/ (Division).
% (Modulus).
Relational (comparison) operators:
Compare two values and return a boolean result (true or false).
== (Equal to).
!= (Not equal to).
< (Less than).
> (Greater than).
<= (Less than or equal to).
>= (Greater than or equal to).
Logical operators:
Combine or invert boolean expressions.
&& (Logical AND).
|| (Logical OR).
! (Logical NOT).
Bitwise operators:
Perform bit-level operations on integral values.
& (AND).
| (OR).
^ (XOR).
~ (Complement).
<< (Left shift).
>> (Right shift).
Assignment operators:
Assign values to variables, sometimes performing operations during
assignment.
= (Simple assignment).
+= (Add and assign).
-= (Subtract and assign).
= (Multiply and assign).
/= (Divide and assign).
Unary operators:
Operate on a single operand.
++ (Increment).
-- (Decrement).
+ (Unary plus).
- (Unary minus).
Ternary operator:
A compact form of an if-else statement.
? : (Conditional operator).
Type casting operators:
Convert one data type to another.
static_cast.
dynamic_cast.
const_cast.
reinterpret_cast.
Comma operator (,):
Evaluates multiple expressions from left to right, returning the value of
the last expression.
Member access operators:
Access members of classes or objects.
. (Direct member access).
-> (Indirect member access through a pointer).
Memory management operators:
Allocate and deallocate dynamic memory.
new (Allocates memory).
new[] (Allocates memory for arrays).
delete (Deallocates memory).
delete[] (Deallocates memory for arrays).
Sizeof operator (sizeof):
Returns the size, in bytes, of a data type or object.
Typeid operator (typeid):
Returns the type information of an expression or a type.
Operator Overloading
Explanation
Operator overloading allows you to define custom behavior for operators
(e.g., +, -, =, etc.) when they are used with user-defined types
(classes or structs).
The RetType depends on the output of the operator which you want to
overload. The para_list depends on the inputs to the operator and the
object you want to operate on.
Syntax
RetType operatorSymbol( para_list );
Copy-assignment Operator
Default Copy-assignment Operator
Explanation
The default copy-assignment operator is generated by the compiler if no
user-defined copy-assignment operator is provided.
It handles shallow copies, which may lead to issues like double
deletion if pointers are involved.
The = default syntax explicitly requests the compiler to generate the
default copy-assignment operator.
The copy-assignment operator can be overloaded to handle deep copies,
manage resources appropriately, and perform self-assignment checks.
The parameter of a copy constructor and copy assignment operator should
not be passed by value, as this can lead to issues.
When passing the argument by value, the copy constructor will be called to
create a temporary object for the parameter.
This temporary object creation requires another call to the copy
constructor, which leads to a recursive cycle.
The cycle continues until the call stack overflows, causing a stack
overflow error.
In other words, passing by value in the copy constructor or copy assignment
operator triggers an infinite loop, as each invocation requires another
copy of the argument, which again invokes the copy constructor.
Syntax
ClassName& operator=( const ClassName& other ) {
// If copy to the same object, nothing need to be done.if( this != &other ) {
// Custom copy logic here.// Copy the other object's resources into this object.
}
return *this; // Returning *this enables chained assignments.
};
Move-assignment Operator
Default Move-assignment Operator
Explanation
The default move-assignment operator is generated by the compiler if no
user-defined copy-assignment operator is provided.
It handles shallow moves, which may lead to issues like double
deletion if pointers are involved.
The state of the moved-from object is unspecified but valid after the
operation.
The = default syntax explicitly requests the compiler to generate the
default move-assignment operator.
Syntax
ClassName& operator=( ClassName&& ) = default;
Move-assignment Operator Overloading
Explanation
The move-assignment operator can be overloaded to control how resources are
transferred between objects.
It handles deep moves, which deals with issues like double deletion
if pointers are involved.
Syntax
ClassName& operator=( ClassName&& other ) noexcept {
// If moved to the same object, nothing need to be done.if( this != &other ) {
// Custom move logic here.// Release this object's resources.// Move the other object's resources into this object.
}
return *this; // Returning *this enables chained assignments.
};
Conversion Operator
Explanation
The conversion operator specifies how to convert an object of the class to
a designated target type, which can be beneficial for implicit conversions
or explicit type casting.
Implicit conversion: If defined, the conversion can occur automatically
in certain contexts (e.g., passing an object to a function expecting a
different type).
Explicit conversion: If marked with explicit, the conversion will only
occur when explicitly requested, thus preventing unintended conversions.
If we implement a smart pointer by ourselves, pass it as a reference into
a function and want to judge it if it is a null pointer, bool
conversion operator is needed.
If a class only possesses one useful member, and we want to assign it
to a primitive-type variables outside of the class without calling any
function, `bool conversion operator is need.
Problem: less readability of code, not work if functions have been
overloaded.
for ( auto& var : container );
for ( auto& [var1, var2, ...] : container );
Notes
It is important to ensure that memory is deallocated using the
corresponding operator that was used for allocation to avoid
undefined behavior.
Using ternary operators to replace an if-else statement when
initializing an object can make it slightly faster. Using nested
ternary operators can be confusing, so we should avoid using them.
The compiler is smart enough so that it can optimize some arithmic
operations to some bitwise operations, for example, 5 x 16 to 5 << 4.
Short circuit evaluation may cause Logical OR and Logical AND to not evaluate
the right operand. Avoid using expressions with side effects in conjunction
with these operators. Only the built-in versions of these operators perform
short-circuit evaluation. If you overload these operators to make them work
with your own types, those overloaded operators will not perform
short-circuit evaluation.
Avoid using the bitwise operators with signed operands, as many operators
will return implementation-defined results prior to C++20 or have other
potential gotchas that are easily avoided by using unsigned operands (or
std::bitset).