OOP · ENCT 151

Ch 4. Operator Overloading

5 hours · 7 marks

Operator overloading gives operators (+, -, ==, etc.) additional meaning when applied to objects of a user-defined class — an example of compile-time (static) polymorphism.

4.1 Overloadable and Non-overloadable Operators

OverloadableNon-overloadable
+ - * / % = == != < > <= >= ++ -- [] () -> new delete << >> && || ! ~ & | ^ etc. :: (scope resolution), . (member access), .* (pointer-to-member), ?: (ternary), sizeof

4.2 Syntax of Operator Overloading

returnType operator symbol (parameter list) {
    // function body defining new behaviour
}

The keyword operator followed by the operator symbol forms the function name.

4.3 Operator Overloading Using Member Operator Functions

class Complex {
    float real, imag;
public:
    Complex(float r=0, float i=0): real(r), imag(i) {}
    Complex operator+(Complex c) {              // member function -- 1 explicit argument for binary +
        return Complex(real + c.real, imag + c.imag);
    }
    void show() { cout << real << " + " << imag << "i"; }
};
int main() {
    Complex c1(2,3), c2(1,4);
    Complex c3 = c1 + c2;   // calls c1.operator+(c2)
    c3.show();               // 3 + 7i
}

4.4 Operator Overloading Using Non-member (Friend) Functions

class Complex {
    float real, imag;
public:
    Complex(float r=0, float i=0): real(r), imag(i) {}
    friend Complex operator+(Complex a, Complex b);  // non-member -- 2 explicit arguments
};
Complex operator+(Complex a, Complex b) {
    return Complex(a.real + b.real, a.imag + b.imag);
}

Non-member (often friend) functions are required when the left operand is not an object of the class (e.g., overloading 2 + c1, or overloading <</>> for streams where the left operand is cout/cin).

4.5 Unary Operator Overloading

Unary operators (-, ++, --, !) act on a single object — as a member function they take zero explicit arguments.

class Counter {
    int count;
public:
    Counter(int c=0): count(c) {}
    Counter operator++() {          // prefix ++obj
        count++;
        return *this;
    }
    Counter operator++(int) {       // postfix obj++ (dummy int parameter distinguishes it)
        Counter temp = *this;
        count++;
        return temp;
    }
    Counter operator-() {            // unary minus: negates count
        return Counter(-count);
    }
    void show() { cout << count; }
};

4.6 Binary Operator Overloading

Binary operators (+, -, ==, etc.) act on two operands — as a member function they take one explicit argument (the right operand; the left operand is the calling object, accessed implicitly via this).

class Vector2D {
    float x, y;
public:
    Vector2D(float a=0, float b=0): x(a), y(b) {}
    Vector2D operator+(Vector2D v) { return Vector2D(x+v.x, y+v.y); }
    bool operator==(Vector2D v) { return x==v.x && y==v.y; }
};

4.7 Type Conversion Between Objects

Three conversion situations:

class Fahrenheit {
    float temp;
public:
    Fahrenheit(float t): temp(t) {}          // int/float -> Fahrenheit (converting constructor)
    operator float() { return temp; }         // Fahrenheit -> float (conversion operator)
};
int main() {
    Fahrenheit f = 98.6;   // float converted to Fahrenheit object
    float t = f;             // Fahrenheit object converted to float
}

4.8 Explicit Constructors

By default, a single-argument constructor also acts as an implicit conversion from that argument type to the class type, which can cause unintended/surprising conversions. The explicit keyword disables this implicit conversion, allowing the constructor to be used only for direct/explicit initialization.

class Box {
    int size;
public:
    explicit Box(int s): size(s) {}
};
Box b1(5);        // OK — direct initialization
Box b2 = 5;        // ERROR — implicit conversion disallowed by 'explicit'
Box b3 = Box(5);   // OK — explicit conversion

Most Probable Questions

Q1. What is operator overloading? Write a program to overload the + operator to add two complex numbers. 7 marks
Operator overloading lets an existing operator perform a user-defined operation on objects of a class (compile-time polymorphism). See the full Complex example in section 4.3.
Q2. Differentiate between overloading a binary operator as a member function and as a friend function. 5 marks
As a member function, a binary operator takes only one explicit argument (the right operand); the left operand must be an object of the class (calling object). As a friend/non-member function, it takes two explicit arguments and does NOT require the left operand to be of the class type — needed, e.g., to support int + object or to overload stream operators <</>>.
Q3. Write a program to overload the unary minus operator for a class Distance (feet/inches). 6 marks
class Distance {
    int feet;
public:
    Distance(int f=0): feet(f) {}
    Distance operator-() { return Distance(-feet); }   // unary: no explicit argument
    void show() { cout << feet; }
};
int main() {
    Distance d1(10), d2;
    d2 = -d1;
    d2.show();   // -10
}
Q4. What operators cannot be overloaded in C++? 3 marks
:: (scope resolution), . (member access / dot), .* (pointer-to-member access), ?: (ternary conditional), and sizeof cannot be overloaded (see section 4.1).
Q5. Explain the difference between overloading prefix and postfix increment operators. 5 marks
Prefix ++obj is overloaded as operator++() with no parameters — it increments and then returns the updated object. Postfix obj++ is overloaded as operator++(int) — the dummy int parameter (never used) exists purely to let the compiler distinguish it from the prefix version; it typically saves the old state in a temporary, increments, and returns the temporary (old value). See section 4.5.
Q6. What is an explicit constructor? Why is it used? 4 marks
A constructor marked explicit cannot be used for implicit type conversions — it can only be invoked through direct or explicit initialization. It is used to prevent accidental, unintended conversions that could introduce subtle bugs (e.g., passing a plain int where a class object was expected). See section 4.8.
Q7. Explain type conversion between a basic type and a class object, and between two class objects. 5 marks
Basic type → class object uses a single-argument (converting) constructor. Class object → basic type uses a conversion operator function of the form operator type() defined inside the class, with no return type specified and no arguments. Class-to-class conversion uses either a converting constructor in the destination class or a conversion operator in the source class (see section 4.7).
Q8. Write a program to overload the == operator to compare two objects of a class Point. 5 marks
class Point {
    int x, y;
public:
    Point(int a=0, int b=0): x(a), y(b) {}
    bool operator==(Point p) { return (x==p.x && y==p.y); }
};
int main() {
    Point p1(2,3), p2(2,3);
    if (p1 == p2) cout << "Equal";
    else cout << "Not equal";
}
← Chapter 3 Next: Chapter 5 — Inheritance →