Правила программирования на Си и Си++


         

в таблице виртуальных функций, которые


_vtable = _employee_vtable; // Создается таблица виртуальных
}                           // функций.
Компилятор переписал те ячейки в таблице виртуальных функций, которые содержат замещенные в производном классе виртуальные функции. Виртуальная функция (virtf), которая не была замещена в производном классе, остается инициализированной функцией базового класса.
Когда вы создаете во время выполнения объект таким образом:
storable *p = new employee();
то компилятор на самом деле генерирует:
storable *p;
p = (storable *)malloc( sizeof(employee) );
_employee_ctor( p );
Вызов _employee_ctor()
сначала инициализирует компонент базового класса посредством вызова _sortable_ctor(), которая добавляет таблицу этой виртуальной функции к своей таблице и выполняется. Затем управление передается обратно к _employee_ctor() и указатель в таблице виртуальной функции переписывается так, чтобы он указывал на таблицу производного класса.
Отметьте, что, хотя p теперь указывает на employee, код p->print()
генерирует точно такой же код, как и раньше:
( p->_vtable[0] )( p );
Несмотря на это, теперь p
указывает на объект производного класса, поэтому вызывается версия print()
из производного класса (так как _vtable в объекте производного класса указывает на таблицу производного класса). Крайне необходимо, чтобы эти две функции print()
располагались в одной и той же ячейке своих таблиц смешений, но это обеспечивается компилятором.
Возвращаясь к основному смыслу данного правила, отметим, что при рассмотрении того, как работает конструктор, важен порядок инициализации. Конструктор производного класса перед тем, как он что-либо сделает, вызывает конструктор базового класса. Так как _vtable в конструкторе базового класса указывает на таблицу виртуальных функций базового класса, то вы лишаетесь доступа к виртуальным функциям базового класса после того, как вызвали их. Вызов print в конструкторе базового класса все так же дает:
( this->_vtable[0] )( p );
но _vtable
указывает на таблицу базового класса и _vtable[0]
указывает на функцию базового класса. Тот же самый вызов в конструкторе производного класса даст версию print()
производного класса, потому что _vtable
будет перекрыта указателем на таблицу производного класса к тому времени, когда была вызвана print().
Хотя я и не показывал этого прежде, то же самое происходит в деструкторе. Первое, что делает деструктор, — это помещает в _vtable
указатель на таблицу своего собственного класса. Только после этого он выполняет написанный вами код. Деструктор производного класса вызывает деструктор базового класса на выходе (в самом конце — после того, как выполнен написанный пользователем код).

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





Forekc.ru
Рефераты, дипломы, курсовые, выпускные и квалификационные работы, диссертации, учебники, учебные пособия, лекции, методические пособия и рекомендации, программы и курсы обучения, публикации из профильных изданий