Pull to refresh
120
0
Андрей Неволин @TechThink

User

Send message
Пожалуйста, см. мой ответ выше для «kaladhara». Я попытался пояснить, что именно я имел в виду под «поддержкой полиморфизма».
Попробую пояснить.
Я не хотел слишком подробно разбирать этот пример, что привело, видимо, к слишком сумбурному тексту.
Дело в том, что мы с вами вкладываем разный смысл в слово «поддерживает».
Конечно же, любой компилятор для C++ поддерживает полиморфизм в том смысле, что строго выполняет требования стандарта языка C++. Но я имел в виду немного другое.

Продолжим разбор примера.
Что происходит в динамике (т.е. во время выполнения программы), когда необходимо выполнить инструкцию «int value = ptr->func();»

А происходит примерно следующее:
1) из участка памяти, соответствующего экземпляру класса, на который указывает «ptr», берется указатель на таблицу виртуальных функций
2) из таблицы виртуальных функций достается указатель на функцию «func»
3) таким образом, мы получили указатель именно на ту версию виртуальной функции «func», которая соответствует конкретному типу класса. Лишь на этом этапе мы можем, наконец, вызвать «func».

Мы видим, что реализованный напрямую механизм виртуальных функций приводит к дополнительным косвенностям: в коде, вместо вызова конкретной функции, стоит вызов функции через указатель. Мало того, что это замедляет сам вызов, это не дает компилятору возможности выполнить подстановку вызова (inline) просто напросто потому, что мы не знаем, какой вызов подставлять (т.к. у нас есть несколько версий функции «func»).

Задача оптимизирующего компилятора состоит в том, чтобы как можно больше узнать о типе класса, для которого вызывается виртуальная функция. А это довольно нетривиальная (в общем случае) задача.

В рассмотренном выше примере компилятор мог действовать примерно так:
1) мы видим, что «ptr» может указывать только на класс типа «A»
2) значит, вызываться может только версия «func», определенная для класса «A»
3) заменяем вызов через таблицу виртуальных функций непосредственно на вызов нужной версии
4) теперь, когда у нас есть конкретный вызов, мы можем его попросту подставить.

Таким образом, у нас вообще не остается вызова. Остается просто присваивание «value = 5».
Данная запись является вводной для цикла постов о принципах работы оптимизирующих компиляторов, о сложностях их использования и о бонусах, которые можно получить от использования хорошего компилятора.

Если вам интересны какие-то определенные темы, оставляйте запросы. Попробуем рассмотреть то, что интересно именно вам.

Information

Rating
Does not participate
Registered
Activity