**Полиморфизм** - способность одного и того же оператора (команды, функции, действия и т. д.) приобретать различные смыслы (значения) в зависимости от обрабатываемых данных.
1. Перегрузка - преобразование типов данных
2. Перегрузка функций
3. Перегрузка операторов 
## 1. Перегрузка - преобразование типов данных
Перегрузка - преобразование типов данных необходимо для совмещения и использования разных типов данных.  
```cpp
int + float (5 + 6.7)
float + float (5.0 + 6.7)
float i = 11.7;
int i = 11;
```
Для преобразования типов классов к более узкому типу данных используются специальная компонентная функция `operator type()`. Функция не имеет параметров и возвращаемого типа.  
## 2. Перегрузка функций
#### Алгоритм выбора перегруженной функции
1. Найти среди этих перегруженных функций ту, у которой есть совпадение по количеству параметров
2. Проверяется строгое соответствие типу данных
3. Если типы не совпадают, компилятор применяет стандартное повышение типа
4. Стандартное преобразование типа (`void* -> тип*`)
5. Компилятор будет пробовать применять определенные пользователем преобразования типов данных
6. Компилятор будет проверять, есть ли функция `void f(...)` - функция с переменным числом параметров

Если ничего не сработает - будет синтаксическая ошибка
## 3. Перегрузка операторов
Перегружать можно и бинарные, и унарные операторы. Перегружать их можно и компонентными, и внешними функциями. Параметрами у этих функций должны быть либо объекты, либо ссылки на них, но не указатели.  
Можно перегружать только нестатической компонентной функцией: `=, [], (), ->, new, delete`.  
Перегружать нельзя (и не нужно): `::, sizeof, ?:, ., .*`
```cpp
pixel& operator=(const pixel& other)
```
Если в классе есть копирующий конструктор, то в этом классе необходимо иметь функцию, содержащую перегрузку оператора присваивания.  
```cpp
pixel operator+(pixel b);
friend pixel operator+(pixel a, pixel b);
pixel& operator++();
pixel& operator++(int);
pixel t1, t2, t3;
t3 = t1 + t2;
t1.operator+(t2);
operator+(t1, t2);
```
  
```cpp
class vect {
private:
	float* p;
	int k;
public:
	float& element(int i);
};

vect v1, v2, v3;
v1.element(3);
v2.element(10);
v3.element(k);
```
  
```cpp
class matrix {
private:
	float** p;
	int k1, k2;
public:
	float& element(int i, int j);
	float& operator()(int i, int j);
}

float& matrix::operator()(int i, int j) {
	return p[i][j];
}

matrix m1, m2, m3;
m1.element(5, 7);
m1(5, 7);
m2(10, 11);
```
## Дружественные функции
`friend f()` - **дружественная функция**. Она даёт доступ к приватным элементам класса. Используется в том числе для перегрузки бинарных операторов.
```cpp
class A {
public:
	void f_A();
	friend void f();
};

class B {
public:
	void f_B();
	friend void f();
	friend void A::f_A();
	friend class C;
};
```
