1. Operator Overloading

Function Call Operator ()

The function call operator allows objects to be used as if they were functions. Objects that implement this operator are called "functors."

class Complex {
private:
    int real;
    int imag;
public:
    Complex(int real = 0, int imag = 0) {
        this->real = real;
        this->imag = imag;
    }

    // Function call operator overloading
    void operator()(int real, int imag) {
        this->real = real;
        this->imag = imag;
    }

    void printRecord() {
        cout << "Real Number: " << this->real << endl;
        cout << "Imag Number: " << this->imag << endl;
    }
};

int main() {
    Complex c1;
    c1(10, 20);  // Using the object like a function: c1.operator()(10, 20)
    c1.printRecord();  // Output: Real Number: 10, Imag Number: 20
    return 0;
}

Benefits of Functors:

Arrow Operator ->

The arrow operator is used to create smart pointer-like objects that provide automatic resource management.

class Array {
private:
    int* data;
    int size;
public:
    Array(int size) : size(size) {
        data = new int[size]();
    }

    void acceptRecord() {
        cout << "Enter " << size << " elements: ";
        for(int i = 0; i < size; i++)
            cin >> data[i];
    }

    void printRecord() {
        cout << "Array elements: ";
        for(int i = 0; i < size; i++)
            cout << data[i] << " ";
        cout << endl;
    }

    ~Array() {
        delete[] data;
    }
};

class AutoPtr {
private:
    Array* ptr;
public:
    AutoPtr(Array* ptr) : ptr(ptr) {}

    // Arrow operator overloading
    Array* operator->() {
        return ptr;
    }

    ~AutoPtr() {
        delete ptr;  // Automatic cleanup
    }
};

int main() {
    // No need to call delete manually
    AutoPtr obj(new Array(3));
    obj->acceptRecord();  // Equivalent to: obj.operator->()->acceptRecord();
    obj->printRecord();   // Equivalent to: obj.operator->()->printRecord();
    return 0;
}

2. Conversion Functions

Conversion functions allow converting between user-defined types and fundamental types. There are three main types of conversion functions:

1. Single Parameter Constructor

Converts from fundamental type to user-defined type:

class Complex {
private:
    int real;
    int imag;
public:
    // Single parameter constructor acts as conversion function
    Complex(int r) : real(r), imag(0) {
        cout << "Conversion from int to Complex" << endl;
    }

    Complex(int r, int i) : real(r), imag(i) {}

    void printRecord() {
        cout << "Real: " << real << ", Imag: " << imag << endl;
    }
};

int main() {
    int number = 10;
    Complex c1 = number;  // Implicitly calls Complex(number)
    c1.printRecord();     // Output: Real: 10, Imag: 0
    return 0;
}

Using explicit keyword to prevent implicit conversion:

class Complex {
private:
    int real;
    int imag;
public:
    // Prevents implicit conversion
    explicit Complex(int r) : real(r), imag(0) {
        cout << "Explicit conversion from int to Complex" << endl;
    }

    // Other methods...
};

int main() {
    int number = 10;
    // Complex c1 = number;  // Error: implicit conversion not allowed
    Complex c1(number);     // Explicit conversion is allowed
    Complex c2 = static_cast<Complex>(number);  // Also allowed
    return 0;
}

2. Assignment Operator

Allows assignment from one type to another: