C++ 3d.Комментарии



Виртуальные функции - часть 2


К счастью, vtbl содержит разные записи для каждого из вариантов вызова, так что решение, очевидно, есть. На практике, чаще всего, используется один из следующих способов:

  1. В таблицу vtbl добавляется дополнительная колонка -- vdelta. Тогда в процессе вызова виртуальной функции кроме адреса функции из vtbl извлекается и дельта, чье значение добавляется к ptr: addr=vtbl[index].vaddr; // извлекаем адрес функции vfun delta=vtbl[index].vdelta; // извлекаем дельту, зависящую от способа вызова vfun (*addr)(ptr+delta); // вызываем vfun

    Существенным недостатком данного способа является заметное увеличение размеров vtbl и значительные накладные расходы времени выполнения: дело в том, что абсолютное большинство вызовов виртуальных функций не требует коррекции значения ptr, так что соответствующие им значения vdelta будут нулевыми. Достоинством -- возможность вызова виртуальной функции из ANSI C кода, что важно для C++ -> C трансляторов.

  • Более эффективным решением является создание нескольких точек входа для одной и той же виртуальной функции, каждая из которых соответствующим образом корректирует значение ptr (если это вообще нужно): vfun_entry_0: // ... // собственно код vfun // ... return;

    vfun_entry_1: ptr+=delta_1; // корректируем значение ptr goto vfun_entry_0; // и переходим к телу vfun

    В этом случае vtbl содержит только адреса соответствующих точек входа и никаких напрасных вычислений не требуется. Специфическим недостатком данного способа является невозможность его реализации средствами ANSI C.

  • Интересное и достаточно подробное описание представления объектов и реализации механизма вызова виртуальных функций можно найти в статье C++: Under the Hood. Она описывает реализацию, использованную разработчиками MSVC.




    Содержание  Назад  Вперед