Overloading means piling on another definition for a name.

Function Overloading

C++ compiler can distinguish functions with the same name but different parameters

// overloading1.cpp
void output_type(int) { std::cout << "in" << std::endl;}
void output_type(float) { std::cout << "float" << std::endl;}

int main() {
	output_type(1); // will print int
	output_type(1.f); // will print float
	return 0
}

However, it cannot distinguish functions with the same name and parameters but different return types.

Operator Overloading

Operators like + and << are like functions:

C++ allows us to define new classes, and we can define new meanings for operators (+-*/¡—&=[]==!=<<, etc.)so we can use them on these type.

Operator overloading differs from function overriding, where we replace a definition of a name

To specify a new definition for an operator with symbol S, we define a method called operatorS.
The compiler understands that expressions using the infix operator + applied to the types specified in the method should map to the above function.

Example: Output Operator

If we had a variable const std::vector<int> vec = {1,2,3}; can make std::cout << vec <<std::endl work by defining the appropriate function.

std::ostream& operator<<(std::ostream& os, const std::vector<int>& vec) {
	for (std::vector<int>::const_iterator it = vec.cbegin();
	it!=vec.cend(); ++it) {
		os<<*it<<' ';
	}
	return os;
}

To output a value, we may need access to instance variables, which are private. However, we can't make operator<< a member of the Rational class (described in the next section) since a member function would get the object of that class type as its implicit argument, and the first argument for << needs to be std::ostream type (not Rational).

class Rational{
public:
	...
	friend ostream& operator<<(ostream& os, const Rational &r);
	...
private:
}

Assignment Operator

operator= is called when assigning one class variable to another except for initialization; copy constructor handles that.

Example:

Image& operator=(const Image& o) {
	delete[] image; // deallocate previous image memory
	nrow = o.nrow;
	ncol = o.ncol;
	image = new char[nrow*ncol];
	for (int i = 0; i < nrow * ncol; i++) {
		image[i] = o.image[i];
	)
	return *this; // for chaining
}

Operator as Instance Method

Suppose we have a defined class Rational that stores an int numerator and int denominator, the best way to declare a method named operator+ to work two Rational objects would be as a member of the Rational class since the method needs to access the private instance variables:

Rational operator+ (const Rational& right) const;

Full class:

// operator4.h
class Rational {
public: 
	Rational operator+(const Rational& right) const;
	
private:
	int num;
	int den;
};

// operator4.cpp
Rational Rational::operator+(const Rational& right) const {
	int sum_num =
	this->num * right.den + right.num * this->den;
	int sum_den = this->den * right.den;
	Rational result(sum_num, sum_den);
	return result;
}

Copy constructor

If you don't define a copy constructor, a default one is created for you (implicit; compiler-generated) which performs a shallow copy (simple field-by-field copy). This would not work if your class manages heap memory.

Copy constructor is used:

Copy constructor initializes a class variable as a copy of another.

ClassName(const ClassName&)