Elective Object Oriented Programming in C++

Object Oriented Programming in C++Unit 79 min read

Operator Overloading & Type Conversion: Rules, Examples & Real-World Use

Unit 7 of Object Oriented Programming in C++ covers operator overloading (how to redefine operators like +, -, << for custom objects), type conversion (implicit/explicit), and their applications in financial calculations, string manipulation, and STL containers. Learn with visual traces, code examples, and real-world t

Key Concepts & Rules

1. Operator Overloading Basics

Operator overloading allows you to redefine how operators work for user-defined types (classes/structs). It must:

  • Use the operator keyword.
  • Have at least one user-defined type as an operand.
  • Cannot change operator precedence or associativity.
  • Cannot introduce new operators (only overload existing ones).
classDiagram
    class OperatorOverloading {
        +operator+() Overloads +
        +operator<<() Overloads << for output
        +operator>>() Overloads >> for input
        +operator=() Overloads assignment
        +operator[]() Overloads array access
    }
    OperatorOverloading --> "1" Operator : "Uses"
    Operator --> "2" Operand : "Requires at least one user-defined type"

Example: Overloading + for a Complex class.

class Complex {
    float real, imag;
public:
    Complex(float r = 0, float i = 0) : real(r), imag(i) {}
    Complex operator+(Complex const& obj) {
        Complex res;
        res.real = real + obj.real;
        res.imag = imag + obj.imag;
        return res;
    }
};

Trace for Complex c1(3,4), c2(5,6); Complex c3 = c1 + c2;

Step c1.real c1.imag c2.real c2.imag c3.real c3.imag
1 3 4 5 6 0 0
2 3 4 5 6 8 10

2. Overloadable Operators

Category Operators
Arithmetic +, -, *, /, %, +=, -=, *=, /=
Relational ==, !=, <, >, <=, >=
Bitwise &, `
Logical &&, ||, !
Assignment =, +=, -=, etc.
Membership ., ->, .*, ->*
Increment/Decrement ++, -- (prefix/postfix)
Type Conversion (), new, delete, [], () (function call)
Stream <<, >> (for input/output)

Cannot Overload:

  • :: (scope resolution)
  • .* (pointer-to-member)
  • ?: (ternary)
  • sizeof
  • typeid

3. Friend Functions for Overloading

Friend functions are not member functions but can access private members. They are useful for overloading operators when the operation is symmetric (e.g., + between two objects).

class Distance {
    int feet, inches;
public:
    Distance(int f, int i) : feet(f), inches(i) {}
    friend Distance operator+(Distance d1, Distance d2);
};

Distance operator+(Distance d1, Distance d2) {
    Distance temp;
    temp.feet = d1.feet + d2.feet;
    temp.inches = d1.inches + d2.inches;
    return temp;
}

Trace for Distance d1(3,4), d2(5,6); Distance d3 = d1 + d2;

[object Object]0[object Object]1[object Object]2
Step-by-step trace of `Distance d3 = d1 + d2;` (feet and inches addition)

In the Real World

  1. eSewa Transactions

    • Idea Used: Operator overloading for + to combine transaction amounts.
    • How? When you add multiple payments (e.g., electricity + water bill), eSewa internally uses overloaded + to sum Transaction objects, storing total amount and fees in a single Payment object.
  2. Daraz Order Queue

    • Idea Used: Overloaded << for Order class to print order details (ID, customer, items) in a readable format.
    • How? When you check your order status, Daraz’s backend uses cout << order; (overloaded <<) to display:
      Order ID: 12345
      Customer: John Doe
      Items: [Laptop, Mouse]
      Status: Processing
      
  3. Khalti Loan Interest Calculation

    • Idea Used: Overloaded - to subtract principal from loan balance after each EMI payment.
    • Worked Example:
      class Loan {
          double principal, interestRate;
      public:
          Loan(double p, double r) : principal(p), interestRate(r) {}
          Loan operator-(double payment) {
              Loan temp(principal - payment, interestRate);
              return temp;
          }
      };
      
      Trace for Loan loan(10000, 0.1); loan = loan - 500;
      Step loan.principal loan.interestRate
      1 10000 0.1
      2 9500 0.1

Type Conversion in C++

1. Implicit Conversion

Automatically converts one type to another when safe (e.g., int to double). For user-defined types, you can define a conversion constructor or operator().

Example: Convert int to Distance

class Distance {
    int feet, inches;
public:
    Distance(int f = 0, int i = 0) : feet(f), inches(i) {}
    // Conversion constructor
    Distance(int totalInches) {
        feet = totalInches / 12;
        inches = totalInches % 12;
    }
};

Trace for Distance d = 25; (25 inches)

Step totalInches feet inches
1 25 2 1

2. Explicit Conversion

Use explicit to prevent implicit conversions (avoids accidental type mismatches).

explicit Distance(int totalInches) { ... }

Now, Distance d = 25; is invalid—you must write Distance d(25);.


3. User-Defined to User-Defined Conversion

Convert one class to another using conversion functions (member functions returning the target type).

Example: Convert Time to Seconds

class Time {
    int hours, minutes;
public:
    operator int() { return hours * 3600 + minutes * 60; }
};

class Seconds {
    int totalSeconds;
public:
    Seconds(int s) : totalSeconds(s) {}
};

int main() {
    Time t(2, 30); // 2 hours 30 minutes
    Seconds s = t; // Calls operator int() → 9000 seconds
}

Trace for Seconds s = Time(1, 30);

Step Time.hours Time.minutes operator int() Seconds.totalSeconds
1 1 30 13600 + 3060 = 5400 5400

Comparison Table: Operator Overloading vs. Type Conversion

Feature Operator Overloading Type Conversion
Purpose Redefine operators for custom types. Convert between types (built-in or user-defined).
Syntax operator+, operator<<, etc. Conversion constructor or operator T().
Use Case Math operations (+, -), I/O (<<, >>). Initialization, function arguments.
Safety Can lead to ambiguous code if overused. explicit prevents implicit conversions.
Example Complex c3 = c1 + c2; Seconds s = t; (where t is Time).

Common Pitfalls & Best Practices

  1. Ambiguity:

    • Overloading + for two classes can cause ambiguity if both classes define operator+.
    • Fix: Use explicit constructors or friend functions carefully.
  2. Overloading =:

    • Always return a reference to avoid infinite recursion.
    Complex& operator=(Complex const& obj) {
        real = obj.real;
        imag = obj.imag;
        return *this;
    }
    
  3. Overloading []:

    • Useful for custom containers (e.g., Matrix class).
    int& operator[](int index) { return data[index]; }
    
  4. Stream Operators (<<, >>):

    • Overload for debugging or user-friendly output.
    friend ostream& operator<<(ostream& os, const Complex& c) {
        os << c.real << " + " << c.imag << "i";
        return os;
    }
    

Exam Tip

  1. Operator Overloading Questions:

    • Always show the trace of how the operator works (e.g., + for Complex numbers).
    • Explain why you chose a member function vs. a friend function.
    • Common Exam Asks:
      • Overload + for a String class.
      • Overload << for a Student class to print records.
      • Explain how operator= differs from assignment.
  2. Type Conversion Questions:

    • Distinguish between implicit and explicit conversion.
    • Show the conversion path (e.g., int → Distance → Seconds).
    • Common Exam Asks:
      • Write a conversion constructor for Temperature (Celsius to Fahrenheit).
      • Define operator int() for a Date class to return days since epoch.
  3. Real-World Tie:

    • If asked about applications, always mention:
      • eSewa/Khalti: Operator overloading for transaction math.
      • Daraz: Overloaded << for order status.
      • Banks: Type conversion for loan EMI calculations.

Based on the PU BE Computer (PU) syllabus for Object Oriented Programming in C++, unit 7.

Discussion

Loading…