Полиморфизм в C++: практическое руководство
Слово полиморфизм означает «имеющий много форм». Обычно полиморфизм возникает при иерархии классов, связанных наследованием.
Полиморфизм в C++ означает, что вызов функции-члена приведёт к выполнению разных функций в зависимости от типа объекта, вызывающего функцию.
Рассмотрим пример, где базовый класс унаследован двумя другими:
Live Demo#include <iostream>
using namespace std;
class Shape {
protected:
int width, height;
public:
Shape(int a = 0, int b = 0) { width = a; height = b; }
int area() {
cout << "Parent class area :" << endl;
return 0;
}
};
class Rectangle: public Shape {
public:
Rectangle(int a = 0, int b = 0): Shape(a, b) { }
int area() {
cout << "Rectangle class area :" << endl;
return (width * height);
}
};
class Triangle: public Shape {
public:
Triangle(int a = 0, int b = 0): Shape(a, b) { }
int area() {
cout << "Triangle class area :" << endl;
return (width * height / 2);
}
};
int main() {
Shape *shape;
Rectangle rec(10,7);
Triangle tri(10,5);
// адрес Rectangle
shape = &rec;
shape->area();
// адрес Triangle
shape = &tri;
shape->area();
return 0;
}
Результат компиляции и выполнения:
Parent class area : Parent class area :
Причина неверного вывода: вызов area() зафиксирован компилятором как версия базового класса — это статическое разрешение (static linkage) или раннее связывание (early binding).
Теперь сделаем небольшое изменение: добавим ключевое слово virtual перед объявлением area() в базовом классе:
class Shape {
protected:
int width, height;
public:
Shape(int a = 0, int b = 0) { width = a; height = b; }
virtual int area() {
cout << "Parent class area :" << endl;
return 0;
}
};
После этого результатом будет:
Rectangle class area Triangle class area
Теперь компилятор смотрит на содержимое указателя, а не на его тип. Поскольку в *shape хранятся адреса объектов tri и rec, вызываются соответствующие area().
Каждый дочерний класс имеет свою реализацию area(). Так и используется полиморфизм: разные классы с функцией одного имени и тех же параметров, но разной реализацией.
Виртуальные функции
Виртуальная функция — функция в базовом классе, объявленная с ключевым словом virtual. Определение в базовом классе виртуальной функции с другой версией в производном классе сигнализирует компилятору, что мы не хотим статического связывания для этой функции.
Мы хотим, чтобы выбор функции для вызова в любой точке программы основывался на типе объекта, для которого она вызывается. Это называется динамическим связыванием (dynamic linkage) или поздним связыванием (late binding).
Чисто виртуальные функции
Можно захотеть включить виртуальную функцию в базовый класс для переопределения в производном, но без осмысленного определения в базовом. Тогда делают её чисто виртуальной:
class Shape {
protected:
int width, height;
public:
Shape(int a = 0, int b = 0) { width = a; height = b; }
// чисто виртуальная функция
virtual int area() = 0;
};
= 0 сообщает компилятору, что у функции нет тела. Такая виртуальная функция называется чисто виртуальной.
Язык C
- Освоение операторов C++: полное руководство с практическими примерами
- Как передавать массивы в функции в C++: практическое руководство
- Классы и объекты в C++: практическое руководство по объектно-ориентированному программированию
- Дружественные функции и классы в C++: мастерство контроля доступа
- Шаблоны классов в C++: практическое руководство
- Перегрузка операторов в C++: практическое руководство с примерами кода
- Классы хранения в C++: область видимости, время жизни и использование
- Перегрузка в C++: функции и операторы — подробное руководство
- Абстракция данных в C++: разделение интерфейса и реализации
- Инкапсуляция данных в C++: защита вашего кода