optional · CSS study notes
Operator Overloading (extended)
- Operator overloading: redefining the behavior of an existing operator (
+,-,==,<<, etc.) for a user-defined type, so objects can use natural operator syntax instead of a named function call - Implemented as a member function —
ReturnType operator@(Args), where the left operand is the implicit calling object — or as a non-member /friendfunction, needed when the left operand isn't an object of your class (e.g.cout << obj) - Unary operator overloading (one operand, e.g.
-x,++x,x++) vs binary operator overloading (two operands, e.g.x + y) — different parameter counts/signatures - Stream insertion (
<<) / extraction (>>): must be overloaded as non-member/friendfunctions, since the left operand (cout/cin) is not an object of your class - Operators that cannot be overloaded in C++:
::(scope resolution),.(member access),.*(pointer-to-member),?:(ternary),sizeof— common MCQ trap - Copy constructor and assignment operator (
operator=) are special, heavily tested overloads — critical whenever a class manages dynamic memory (the "Rule of Three": defining one of destructor / copy constructor / copy-assignment operator usually means you need all three)
C++ Example — Overloading + and << for a Complex Class
class Complex
{
private:
double real, imag;
public:
Complex(double r = 0, double i = 0) : real(r), imag(i) {}
// member function: overloads binary +
Complex operator+(const Complex& other) const
{
return Complex(real + other.real, imag + other.imag);
}
// friend function: overloads << (left operand is ostream, not Complex)
friend ostream& operator<<(ostream& out, const Complex& c)
{
out << c.real << " + " << c.imag << "i";
return out;
}
};
int main()
{
Complex a(2, 3), b(1, 4);
Complex c = a + b; // calls operator+ instead of a named add() function
cout << c; // calls operator<< -- prints "3 + 7i"
}
Why Overload the Copy Constructor? Shallow vs Deep Copy
class Buffer
{
private:
int* data;
public:
Buffer(int size) { data = new int[size]; }
// Deep copy constructor -- allocates its OWN memory
Buffer(const Buffer& other)
{
data = new int[1];
*data = *other.data;
}
// Without an explicit deep-copy version, the compiler-generated
// copy constructor does a SHALLOW copy: both objects' 'data'
// point to the SAME memory, so destroying one leaves the other
// with a dangling pointer -- a classic CSS exam pitfall.
~Buffer() { delete[] data; }
};
MCQ Trap
operator<</operator>>cannot be overloaded as ordinary member functions of your own class — the left-hand operand must beostream/istream, so they must befriend/non-member functions- Overloading an operator only changes its behavior for your type — it can never change its precedence, associativity, or number of operands