HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-02-26
1 <h2>Полиморфизм</h2>
1 <h2>Полиморфизм</h2>
2 <p>Слово<strong>полиморфизм</strong>происходит от греческого<em>πολύμορφος</em>- "многообразный, имеющий множество форм". В программировании это означает способность<strong>одной и той же команды, функции или метода вести себя по-разному</strong>в зависимости от типа данных, с которыми он работает.</p>
2 <p>Слово<strong>полиморфизм</strong>происходит от греческого<em>πολύμορφος</em>- "многообразный, имеющий множество форм". В программировании это означает способность<strong>одной и той же команды, функции или метода вести себя по-разному</strong>в зависимости от типа данных, с которыми он работает.</p>
3 <p>Пример на Python:</p>
3 <p>Пример на Python:</p>
4 <p>Функция animal_sound() не знает, кто перед ней - Dog или Cat, но работает одинаково с обоими. Это и есть<strong>полиморфизм</strong>.</p>
4 <p>Функция animal_sound() не знает, кто перед ней - Dog или Cat, но работает одинаково с обоими. Это и есть<strong>полиморфизм</strong>.</p>
5 <h2>Принципы ООП</h2>
5 <h2>Принципы ООП</h2>
6 <p>Полиморфизм - один из<strong>четырех базовых принципов объектно-ориентированного программирования (ООП)</strong>наряду с:</p>
6 <p>Полиморфизм - один из<strong>четырех базовых принципов объектно-ориентированного программирования (ООП)</strong>наряду с:</p>
7 <ol><li><p><strong>Инкапсуляцией</strong>- сокрытием деталей реализации.</p>
7 <ol><li><p><strong>Инкапсуляцией</strong>- сокрытием деталей реализации.</p>
8 </li>
8 </li>
9 <li><p><strong>Наследованием</strong>- механизмом повторного использования кода.</p>
9 <li><p><strong>Наследованием</strong>- механизмом повторного использования кода.</p>
10 </li>
10 </li>
11 <li><p><strong>Абстракцией</strong>- выделением значимых свойств объекта.</p>
11 <li><p><strong>Абстракцией</strong>- выделением значимых свойств объекта.</p>
12 </li>
12 </li>
13 </ol><p>Эти принципы связаны логически. Наследование создает иерархию классов, инкапсуляция прячет детали, абстракция задает общие контракты, а полиморфизм позволяет<strong>взаимодействовать с объектами по этому контракту</strong>, не заботясь об их типе.</p>
13 </ol><p>Эти принципы связаны логически. Наследование создает иерархию классов, инкапсуляция прячет детали, абстракция задает общие контракты, а полиморфизм позволяет<strong>взаимодействовать с объектами по этому контракту</strong>, не заботясь об их типе.</p>
14 <h3>Принцип подстановки Лисков (LSP)</h3>
14 <h3>Принцип подстановки Лисков (LSP)</h3>
15 <p>Полиморфизм подтипов невозможен без соблюдения<strong>принципа подстановки Лисков (Liskov Substitution Principle)</strong>. Барбара Лисков сформулировала его в 1987 году так:</p>
15 <p>Полиморфизм подтипов невозможен без соблюдения<strong>принципа подстановки Лисков (Liskov Substitution Principle)</strong>. Барбара Лисков сформулировала его в 1987 году так:</p>
16 <p>Если S - подтип T, то объекты типа T в программе можно заменить объектами типа S без нарушения корректности.</p>
16 <p>Если S - подтип T, то объекты типа T в программе можно заменить объектами типа S без нарушения корректности.</p>
17 <p>Иными словами, дочерний класс<strong>должен сохранять поведение базового</strong>, а не ломать ожидания клиента.</p>
17 <p>Иными словами, дочерний класс<strong>должен сохранять поведение базового</strong>, а не ломать ожидания клиента.</p>
18 <p><strong>Пример нарушения LSP:</strong></p>
18 <p><strong>Пример нарушения LSP:</strong></p>
19 <p>Square нарушает ожидания клиента, потому что меняет семантику методов базового класса. Формально тип совместим, но поведение - нет. Это антипример корректного полиморфизма.</p>
19 <p>Square нарушает ожидания клиента, потому что меняет семантику методов базового класса. Формально тип совместим, но поведение - нет. Это антипример корректного полиморфизма.</p>
20 <h2>Виды полиморфизма</h2>
20 <h2>Виды полиморфизма</h2>
21 <p>Полиморфизм бывает<strong>разных видов</strong>. Классификация зависит от момента связывания (compile-time / run-time) и способа выражения.</p>
21 <p>Полиморфизм бывает<strong>разных видов</strong>. Классификация зависит от момента связывания (compile-time / run-time) и способа выражения.</p>
22 <h3>Полиморфизм подтипов</h3>
22 <h3>Полиморфизм подтипов</h3>
23 <p>Самый классический вид, реализуемый через<strong>наследование</strong>и<strong>интерфейсы</strong>.</p>
23 <p>Самый классический вид, реализуемый через<strong>наследование</strong>и<strong>интерфейсы</strong>.</p>
24 <p>void render(Drawable d) { d.draw(); }</p>
24 <p>void render(Drawable d) { d.draw(); }</p>
25 <p>Метод render() работает с любым объектом, реализующим интерфейс Drawable. Такой подход облегчает расширение API - можно добавить Triangle, не изменяя render().</p>
25 <p>Метод render() работает с любым объектом, реализующим интерфейс Drawable. Такой подход облегчает расширение API - можно добавить Triangle, не изменяя render().</p>
26 <h3>Параметрический полиморфизм</h3>
26 <h3>Параметрический полиморфизм</h3>
27 <p>Характерен для обобщённого программирования -<strong>Generics в Java, C#</strong>или<strong>Templates в C++</strong>. Функция становится универсальной для разных типов.</p>
27 <p>Характерен для обобщённого программирования -<strong>Generics в Java, C#</strong>или<strong>Templates в C++</strong>. Функция становится универсальной для разных типов.</p>
28 <p>Код компилируется отдельно для каждого конкретного типа - так работает<strong>compile-time полиморфизм</strong>.</p>
28 <p>Код компилируется отдельно для каждого конкретного типа - так работает<strong>compile-time полиморфизм</strong>.</p>
29 <h3>Ad hoc-полиморфизм</h3>
29 <h3>Ad hoc-полиморфизм</h3>
30 <p>Это<strong>перегрузка функций и операторов</strong>, когда несколько реализаций имеют одно имя, но разные сигнатуры.</p>
30 <p>Это<strong>перегрузка функций и операторов</strong>, когда несколько реализаций имеют одно имя, но разные сигнатуры.</p>
31 <p>Такой полиморфизм тоже "многоформен", но решается<strong>на этапе компиляции</strong>.</p>
31 <p>Такой полиморфизм тоже "многоформен", но решается<strong>на этапе компиляции</strong>.</p>
32 <h2>Статический и динамический полиморфизм</h2>
32 <h2>Статический и динамический полиморфизм</h2>
33 <p><strong>Статический (compile-time)</strong>реализуется с помощью перегрузки функций, операторов и шаблонов. Все решения принимаются на этапе компиляции, что делает код быстрым, но менее гибким.</p>
33 <p><strong>Статический (compile-time)</strong>реализуется с помощью перегрузки функций, операторов и шаблонов. Все решения принимаются на этапе компиляции, что делает код быстрым, но менее гибким.</p>
34 <p><strong>Динамический (run-time)</strong>работает через<strong>виртуальные функции</strong>и<strong>vtable</strong>. Он позволяет выбирать нужную реализацию<strong>во время выполнения программы</strong>.</p>
34 <p><strong>Динамический (run-time)</strong>работает через<strong>виртуальные функции</strong>и<strong>vtable</strong>. Он позволяет выбирать нужную реализацию<strong>во время выполнения программы</strong>.</p>
35 <h3>Пример на C++</h3>
35 <h3>Пример на C++</h3>
36 <p>class Shape {</p>
36 <p>class Shape {</p>
37 <p>Здесь используется<strong>динамическая диспетчеризация</strong>через таблицу виртуальных функций (vtable).</p>
37 <p>Здесь используется<strong>динамическая диспетчеризация</strong>через таблицу виртуальных функций (vtable).</p>
38 <p><strong>Цена вызова:</strong>динамический полиморфизм чуть медленнее (1-2 % накладных расходов), но современные компиляторы часто<strong>инлайнят</strong>виртуальные вызовы при предсказуемом типе.</p>
38 <p><strong>Цена вызова:</strong>динамический полиморфизм чуть медленнее (1-2 % накладных расходов), но современные компиляторы часто<strong>инлайнят</strong>виртуальные вызовы при предсказуемом типе.</p>
39 <h2>Полиморфизм в популярных языках программирования</h2>
39 <h2>Полиморфизм в популярных языках программирования</h2>
40 <h3>C++</h3>
40 <h3>C++</h3>
41 <ul><li><p>virtual, override - основа динамического полиморфизма.</p>
41 <ul><li><p>virtual, override - основа динамического полиморфизма.</p>
42 </li>
42 </li>
43 <li><p>templates - параметрический вариант.</p>
43 <li><p>templates - параметрический вариант.</p>
44 </li>
44 </li>
45 <li><p>CRTP (Curiously Recurring Template Pattern) - шаблон, позволяющий имитировать виртуальные вызовы на этапе компиляции.</p>
45 <li><p>CRTP (Curiously Recurring Template Pattern) - шаблон, позволяющий имитировать виртуальные вызовы на этапе компиляции.</p>
46 </li>
46 </li>
47 </ul><h3>Java</h3>
47 </ul><h3>Java</h3>
48 <ul><li><p>Поддерживает<strong>динамический полиморфизм</strong>через abstract и interface.</p>
48 <ul><li><p>Поддерживает<strong>динамический полиморфизм</strong>через abstract и interface.</p>
49 </li>
49 </li>
50 <li><p>Перегрузка (overloading) работает статически.</p>
50 <li><p>Перегрузка (overloading) работает статически.</p>
51 </li>
51 </li>
52 <li><p>Generics реализованы через<strong>type erasure</strong>- типы стираются при компиляции, оставляя единый байт-код.</p>
52 <li><p>Generics реализованы через<strong>type erasure</strong>- типы стираются при компиляции, оставляя единый байт-код.</p>
53 </li>
53 </li>
54 </ul><h3>C#</h3>
54 </ul><h3>C#</h3>
55 <ul><li><p>Generics более мощные: типовая информация сохраняется во время выполнения (<strong>reified generics</strong>).</p>
55 <ul><li><p>Generics более мощные: типовая информация сохраняется во время выполнения (<strong>reified generics</strong>).</p>
56 </li>
56 </li>
57 <li><p>virtual, override обеспечивают полиморфизм подтипов.</p>
57 <li><p>virtual, override обеспечивают полиморфизм подтипов.</p>
58 </li>
58 </li>
59 <li><p>dynamic - отдельный механизм позднего связывания.</p>
59 <li><p>dynamic - отдельный механизм позднего связывания.</p>
60 </li>
60 </li>
61 </ul><h3>Python и JavaScript</h3>
61 </ul><h3>Python и JavaScript</h3>
62 <ul><li><p>Основываются на<strong>duck typing</strong>- "если объект крякает как утка, значит, он утка".</p>
62 <ul><li><p>Основываются на<strong>duck typing</strong>- "если объект крякает как утка, значит, он утка".</p>
63 </li>
63 </li>
64 <li><p>Нет формальных интерфейсов (в Python - появились abc и typing.Protocol).</p>
64 <li><p>Нет формальных интерфейсов (в Python - появились abc и typing.Protocol).</p>
65 </li>
65 </li>
66 <li><p>Механизм гибкий, но ошибки проявляются только в рантайме.</p>
66 <li><p>Механизм гибкий, но ошибки проявляются только в рантайме.</p>
67 </li>
67 </li>
68 </ul><h3>C</h3>
68 </ul><h3>C</h3>
69 <ul><li>В классическом C нет ООП, но полиморфизм можно реализовать вручную:</li>
69 <ul><li>В классическом C нет ООП, но полиморфизм можно реализовать вручную:</li>
70 </ul><p>Структура с указателем на функцию - ручная версия виртуального метода.</p>
70 </ul><p>Структура с указателем на функцию - ручная версия виртуального метода.</p>
71 <h2>Практическая реализация</h2>
71 <h2>Практическая реализация</h2>
72 <h3>Overriding vs Overloading vs Operator Overloading</h3>
72 <h3>Overriding vs Overloading vs Operator Overloading</h3>
73 <p>Типичная ошибка - путать overriding и overloading, ожидая полиморфизма, где его нет.</p>
73 <p>Типичная ошибка - путать overriding и overloading, ожидая полиморфизма, где его нет.</p>
74 <h3>Интерфейсы против абстрактных классов</h3>
74 <h3>Интерфейсы против абстрактных классов</h3>
75 <ul><li><p><strong>Интерфейс</strong>определяет контракт (только сигнатуры методов).</p>
75 <ul><li><p><strong>Интерфейс</strong>определяет контракт (только сигнатуры методов).</p>
76 </li>
76 </li>
77 <li><p><strong>Абстрактный класс</strong>может содержать реализацию.</p>
77 <li><p><strong>Абстрактный класс</strong>может содержать реализацию.</p>
78 </li>
78 </li>
79 <li><p>Если нужно описать,<em>что делает объект</em>- используйте интерфейс, если<em>как делает</em>- абстрактный класс.</p>
79 <li><p>Если нужно описать,<em>что делает объект</em>- используйте интерфейс, если<em>как делает</em>- абстрактный класс.</p>
80 </li>
80 </li>
81 </ul><h3>Композиция против наследования</h3>
81 </ul><h3>Композиция против наследования</h3>
82 <p>"Предпочитай композицию наследованию" (GoF)</p>
82 <p>"Предпочитай композицию наследованию" (GoF)</p>
83 <p>Композиция позволяет гибко собирать объекты, избегая жестких иерархий. Например, класс Car может содержать Engine, а не наследоваться от него.</p>
83 <p>Композиция позволяет гибко собирать объекты, избегая жестких иерархий. Например, класс Car может содержать Engine, а не наследоваться от него.</p>
84 <h3>Расширяемость API: фабрики, стратегии, плагины</h3>
84 <h3>Расширяемость API: фабрики, стратегии, плагины</h3>
85 <p>Полиморфизм лежит в основе паттернов:</p>
85 <p>Полиморфизм лежит в основе паттернов:</p>
86 <ul><li><p><strong>Фабричный метод</strong>- создает экземпляры разных подклассов по единому интерфейсу.</p>
86 <ul><li><p><strong>Фабричный метод</strong>- создает экземпляры разных подклассов по единому интерфейсу.</p>
87 </li>
87 </li>
88 <li><p><strong>Стратегия</strong>- позволяет подменять алгоритм на лету.</p>
88 <li><p><strong>Стратегия</strong>- позволяет подменять алгоритм на лету.</p>
89 </li>
89 </li>
90 <li><p><strong>Плагин-архитектура</strong>- динамическое подключение модулей.</p>
90 <li><p><strong>Плагин-архитектура</strong>- динамическое подключение модулей.</p>
91 </li>
91 </li>
92 </ul><h2>Преимущества и ограничения</h2>
92 </ul><h2>Преимущества и ограничения</h2>
93 <p><strong>Плюсы:</strong></p>
93 <p><strong>Плюсы:</strong></p>
94 <ul><li><p>Унификация интерфейсов, читаемость кода.</p>
94 <ul><li><p>Унификация интерфейсов, читаемость кода.</p>
95 </li>
95 </li>
96 <li><p>Возможность расширять функциональность без изменения существующего кода (Open-Closed Principle).</p>
96 <li><p>Возможность расширять функциональность без изменения существующего кода (Open-Closed Principle).</p>
97 </li>
97 </li>
98 <li><p>Повторное использование, модульность.</p>
98 <li><p>Повторное использование, модульность.</p>
99 </li>
99 </li>
100 </ul><p><strong>Минусы:</strong></p>
100 </ul><p><strong>Минусы:</strong></p>
101 <ul><li><p>Усложнение архитектуры при чрезмерных иерархиях.</p>
101 <ul><li><p>Усложнение архитектуры при чрезмерных иерархиях.</p>
102 </li>
102 </li>
103 <li><p>Потери производительности (незначительные, но есть).</p>
103 <li><p>Потери производительности (незначительные, но есть).</p>
104 </li>
104 </li>
105 <li><p>Затрудненная отладка в глубоко наследуемых структурах.</p>
105 <li><p>Затрудненная отладка в глубоко наследуемых структурах.</p>
106 </li>
106 </li>
107 </ul><p>Практический совет: начинайте с композиции и интерфейсов, добавляйте наследование только при явной необходимости.</p>
107 </ul><p>Практический совет: начинайте с композиции и интерфейсов, добавляйте наследование только при явной необходимости.</p>
108 <h2>Частые ошибки, анти-паттерны</h2>
108 <h2>Частые ошибки, анти-паттерны</h2>
109 <ul><li><p><strong>Глубокие иерархии</strong>- трудно сопровождать.</p>
109 <ul><li><p><strong>Глубокие иерархии</strong>- трудно сопровождать.</p>
110 </li>
110 </li>
111 <li><p><strong>Нарушение LSP</strong>- подтип ломает ожидания клиента.</p>
111 <li><p><strong>Нарушение LSP</strong>- подтип ломает ожидания клиента.</p>
112 </li>
112 </li>
113 <li><p><strong>Смешение overloading и overriding</strong>- методы не переопределяются, а перегружаются по ошибке.</p>
113 <li><p><strong>Смешение overloading и overriding</strong>- методы не переопределяются, а перегружаются по ошибке.</p>
114 </li>
114 </li>
115 <li><p><strong>Преждевременная абстракция</strong>- добавление интерфейсов "на будущее".</p>
115 <li><p><strong>Преждевременная абстракция</strong>- добавление интерфейсов "на будущее".</p>
116 </li>
116 </li>
117 </ul><p>Лучше немного дублировать код, чем создавать абстракцию, которую никто не использует.</p>
117 </ul><p>Лучше немного дублировать код, чем создавать абстракцию, которую никто не использует.</p>
118 <h2>FAQ</h2>
118 <h2>FAQ</h2>
119 <p><strong>Что такое полиморфизм в программировании простыми словами?</strong>Это способность функции или метода вести себя по-разному в зависимости от типа объекта, с которым он работает.</p>
119 <p><strong>Что такое полиморфизм в программировании простыми словами?</strong>Это способность функции или метода вести себя по-разному в зависимости от типа объекта, с которым он работает.</p>
120 <p><strong>Чем отличается статический полиморфизм от динамического?</strong>Статический определяется во время компиляции (overload, templates), а динамический - во время выполнения (virtual methods, duck typing).</p>
120 <p><strong>Чем отличается статический полиморфизм от динамического?</strong>Статический определяется во время компиляции (overload, templates), а динамический - во время выполнения (virtual methods, duck typing).</p>
121 <p><strong>Что такое принцип подстановки Лисков?</strong>Это правило, требующее, чтобы объект подкласса можно было использовать вместо базового без изменения поведения программы.</p>
121 <p><strong>Что такое принцип подстановки Лисков?</strong>Это правило, требующее, чтобы объект подкласса можно было использовать вместо базового без изменения поведения программы.</p>
122 <p><strong>Можно ли реализовать полиморфизм в C?</strong>Да, вручную через структуры с указателями на функции - аналог виртуальных методов.</p>
122 <p><strong>Можно ли реализовать полиморфизм в C?</strong>Да, вручную через структуры с указателями на функции - аналог виртуальных методов.</p>
123 <h2>Глоссарий</h2>
123 <h2>Глоссарий</h2>
124 <ul><li><p><strong>Подтип</strong>- тип, совместимый с базовым, удовлетворяющий LSP.</p>
124 <ul><li><p><strong>Подтип</strong>- тип, совместимый с базовым, удовлетворяющий LSP.</p>
125 </li>
125 </li>
126 <li><p><strong>Интерфейс</strong>- набор сигнатур методов без реализации.</p>
126 <li><p><strong>Интерфейс</strong>- набор сигнатур методов без реализации.</p>
127 </li>
127 </li>
128 <li><p><strong>Абстракция</strong>- выделение существенных свойств.</p>
128 <li><p><strong>Абстракция</strong>- выделение существенных свойств.</p>
129 </li>
129 </li>
130 <li><p><strong>Перегрузка (overloading)</strong>- одинаковое имя, разные параметры.</p>
130 <li><p><strong>Перегрузка (overloading)</strong>- одинаковое имя, разные параметры.</p>
131 </li>
131 </li>
132 <li><p><strong>Переопределение (overriding)</strong>- новая реализация метода базового класса.</p>
132 <li><p><strong>Переопределение (overriding)</strong>- новая реализация метода базового класса.</p>
133 </li>
133 </li>
134 <li><p><strong>Vtable</strong>- таблица виртуальных функций, используемая для диспетчеризации вызовов.</p>
134 <li><p><strong>Vtable</strong>- таблица виртуальных функций, используемая для диспетчеризации вызовов.</p>
135 </li>
135 </li>
136 <li><p><strong>Диспетчеризация</strong>- выбор нужной реализации метода.</p>
136 <li><p><strong>Диспетчеризация</strong>- выбор нужной реализации метода.</p>
137 </li>
137 </li>
138 <li><p><strong>Generics/Templates</strong>- механизм параметрического полиморфизма.</p>
138 <li><p><strong>Generics/Templates</strong>- механизм параметрического полиморфизма.</p>
139 </li>
139 </li>
140 <li><p><strong>Duck typing</strong>- поведение определяется набором методов, а не типом.</p>
140 <li><p><strong>Duck typing</strong>- поведение определяется набором методов, а не типом.</p>
141 </li>
141 </li>
142 </ul><h2>Ссылки и источники</h2>
142 </ul><h2>Ссылки и источники</h2>
143 <ul><li><p><em>Barbara Liskov, "Data Abstraction and Hierarchy" (1987)</em></p>
143 <ul><li><p><em>Barbara Liskov, "Data Abstraction and Hierarchy" (1987)</em></p>
144 </li>
144 </li>
145 <li><p><em>Design Patterns: Elements of Reusable Object-Oriented Software</em>- GoF</p>
145 <li><p><em>Design Patterns: Elements of Reusable Object-Oriented Software</em>- GoF</p>
146 </li>
146 </li>
147 <li><p><em>Effective Java</em>- Joshua Bloch</p>
147 <li><p><em>Effective Java</em>- Joshua Bloch</p>
148 </li>
148 </li>
149 <li><p><em>C++ Templates: The Complete Guide</em>- David Vandevoorde</p>
149 <li><p><em>C++ Templates: The Complete Guide</em>- David Vandevoorde</p>
150 </li>
150 </li>
151 <li><p><a>cppreference.com</a>- документация по C++</p>
151 <li><p><a>cppreference.com</a>- документация по C++</p>
152 </li>
152 </li>
153 <li><p><a>docs.oracle.com/javase/tutorial/java/IandI/polymorphism.html</a></p>
153 <li><p><a>docs.oracle.com/javase/tutorial/java/IandI/polymorphism.html</a></p>
154 </li>
154 </li>
155 <li><p><a>python.org/docs</a></p>
155 <li><p><a>python.org/docs</a></p>
156 </li>
156 </li>
157 <li><p><a>Microsoft Learn - Polymorphism in C#</a></p>
157 <li><p><a>Microsoft Learn - Polymorphism in C#</a></p>
158 </li>
158 </li>
159 </ul>
159 </ul>