Skip to content

Latest commit

 

History

History
314 lines (264 loc) · 10.6 KB

Operators.md

File metadata and controls

314 lines (264 loc) · 10.6 KB

Operators

Explanation

  1. Operators are symbols that perform operations on variables or values.
  2. They allow concise data manipulation, comparisons, and control of program logic.
  3. Operators follow specific rules of precedence and associativity to determine the order of evaluation in complex expressions.
  4. Additionally, operators can be overloaded for custom behavior in user-defined types, improving code flexibility and reusability.
  5. In fact, it's a function. It makes our code clearer.

Categories

  1. Arithmetic operators:
    • Perform basic mathematical operations.
    • + (Addition).
    • - (Subtraction).
    • * (Multiplication).
    • / (Division).
    • % (Modulus).
  2. 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).
  3. Logical operators:
    • Combine or invert boolean expressions.
    • && (Logical AND).
    • || (Logical OR).
    • ! (Logical NOT).
  4. Bitwise operators:
    • Perform bit-level operations on integral values.
    • & (AND).
    • | (OR).
    • ^ (XOR).
    • ~ (Complement).
    • << (Left shift).
    • >> (Right shift).
  5. 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).
  6. Unary operators:
    • Operate on a single operand.
    • ++ (Increment).
    • -- (Decrement).
    • + (Unary plus).
    • - (Unary minus).
  7. Ternary operator:
    • A compact form of an if-else statement.
    • ? : (Conditional operator).
  8. Type casting operators:
    • Convert one data type to another.
    • static_cast.
    • dynamic_cast.
    • const_cast.
    • reinterpret_cast.
  9. Comma operator (,):
    • Evaluates multiple expressions from left to right, returning the value of the last expression.
  10. Member access operators:
    • Access members of classes or objects.
    • . (Direct member access).
    • -> (Indirect member access through a pointer).
  11. Memory management operators:
    • Allocate and deallocate dynamic memory.
    • new (Allocates memory).
    • new[] (Allocates memory for arrays).
    • delete (Deallocates memory).
    • delete[] (Deallocates memory for arrays).
  12. Sizeof operator (sizeof):
    • Returns the size, in bytes, of a data type or object.
  13. Typeid operator (typeid):
    • Returns the type information of an expression or a type.

Operator Overloading

Explanation

  1. Operator overloading allows you to define custom behavior for operators (e.g., +, -, =, etc.) when they are used with user-defined types (classes or structs).
  2. 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
  1. The default copy-assignment operator is generated by the compiler if no user-defined copy-assignment operator is provided.
  2. It handles shallow copies, which may lead to issues like double deletion if pointers are involved.
  3. The = default syntax explicitly requests the compiler to generate the default copy-assignment operator.
Syntax
ClassName& operator=( const ClassName& ) = default;
Copy-assignment Operator Overloading
Explanation
  1. The copy-assignment operator can be overloaded to handle deep copies, manage resources appropriately, and perform self-assignment checks.
  2. 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
  1. The default move-assignment operator is generated by the compiler if no user-defined copy-assignment operator is provided.
  2. It handles shallow moves, which may lead to issues like double deletion if pointers are involved.
  3. The state of the moved-from object is unspecified but valid after the operation.
  4. The = default syntax explicitly requests the compiler to generate the default move-assignment operator.
Syntax
ClassName& operator=( ClassName&& ) = default;
Move-assignment Operator Overloading
Explanation
  1. The move-assignment operator can be overloaded to control how resources are transferred between objects.
  2. 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
  1. 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.
  2. Implicit conversion: If defined, the conversion can occur automatically in certain contexts (e.g., passing an object to a function expecting a different type).
  3. Explicit conversion: If marked with explicit, the conversion will only occur when explicitly requested, thus preventing unintended conversions.
Conversion Operator Overloading
Syntax
// `const` function.
operator TargetType() const {
    // Custom conversion logic here.
};
Notes
  1. 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.
  2. 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.
  3. Problem: less readability of code, not work if functions have been overloaded.
  4. Advantange: make code cleaner.

explicit Conversion Operator

  1. Conversion And Casting

new and delete

  1. new and delete

The Usage of the : Operator

  1. Scope resolution operator(::):
    ClassName::member;
    NamespaceName::member;
    EnumclassName::member;
  2. Inheritance.
  3. Member initialization list.
  4. Conditional operator (ternary operator).
  5. Label in goto statements.
    labelName: statement;
  6. Range-based for loop with structured bindings:
    for ( auto& var : container );
    for ( auto& [var1, var2, ...] : container );

Notes

  1. It is important to ensure that memory is deallocated using the corresponding operator that was used for allocation to avoid undefined behavior.
  2. 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.
  3. 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.
  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.
  5. 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).