Слово полиморфизм означает наличие многих форм. Как правило, полиморфизм возникает, когда существует иерархия классов, и они связаны наследованием.
C ++ полиморфизм означает, что вызов функции-члена приведет к выполнению другой функции в зависимости от типа объекта, который вызывает функцию.
Рассмотрим следующий пример, где базовый класс был получен двумя другими классами:
#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); } }; // Main function for the program int main() { Shape *shape; Rectangle rec(10,7); Triangle tri(10,5); // store the address of Rectangle shape = &rec; // call rectangle area. shape->area(); // store the address of Triangle shape = &tri; // call triangle area. shape->area(); return 0; }
Когда приведенный выше код компилируется и выполняется, он дает следующий результат —
Parent class area : Parent class area :
Причиной неправильного вывода является то, что вызов функции area () устанавливается компилятором один раз как версия, определенная в базовом классе. Это называется статическим разрешением вызова функции или статическим связыванием — вызов функции фиксируется до выполнения программы. Это также иногда называют ранним связыванием, потому что функция area () устанавливается во время компиляции программы.
Но теперь давайте внесем небольшую модификацию в нашу программу и предшествуем объявлению area () в классе Shape с ключевым словом virtual, чтобы оно выглядело так:
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
На этот раз компилятор просматривает содержимое указателя, а не его тип. Следовательно, поскольку адреса объектов классов tri и rec хранятся в форме *, вызывается соответствующая функция area ().
Как видите, каждый из дочерних классов имеет отдельную реализацию для области функций (). Вот как обычно используется полиморфизм . У вас есть разные классы с функцией с одинаковым именем и даже одинаковыми параметрами, но с разными реализациями.
Виртуальная функция
Виртуальная функция — это функция в базовом классе, которая объявлена с использованием ключевого слова virtual . Определение в базовом классе виртуальной функции с другой версией в производном классе сигнализирует компилятору, что нам не нужна статическая связь для этой функции.
Мы хотим, чтобы выбор функции, вызываемой в любой заданной точке программы, основывался на типе объекта, для которого она вызывается. Этот вид операции называется динамическим связыванием или поздним связыванием .
Чистые виртуальные функции
Возможно, вы захотите включить виртуальную функцию в базовый класс, чтобы ее можно было переопределить в производном классе, чтобы она соответствовала объектам этого класса, но при этом нет никакого значимого определения, которое вы могли бы дать для функции в базовом классе. ,
Мы можем изменить виртуальную функцию area () в базовом классе на следующую:
class Shape { protected: int width, height; public: Shape(int a = 0, int b = 0) { width = a; height = b; } // pure virtual function virtual int area() = 0; };
= 0 говорит компилятору, что функция не имеет тела, а над виртуальной функцией будет называться чисто виртуальная функция .