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



         

137. Виртуальная функция не является виртуальной, если вызывается из конструктора или деструктора


Это не столько правило, сколько констатация факта, хотя она и будет для многих неожиданностью. Базовые классы инициализируются перед производными классами. К тому же, по-видимому, функции производного класса имеют доступ к данным этого класса; в ином случае не было бы смысла в помещении этих функций в производный класс. Если бы конструктор базового класса мог вызывать функцию производного класса через механизм виртуальных функций, то эта функция могла бы с пользой использовать инициализированные поля данных производного класса.

Чтобы сделать суть кристально ясной, давайте взглянем на то, что происходит под капотом. Механизм виртуальных функций реализован посредством таблицы указателей на функции. Когда вы объявляете класс, подобный следующему:

class storable

{

   int stuff;

public:

   storable( void );

   virtual void print( void              );

   virtual void virtf( void              );

   virtual int  cmp  ( const storable &r ) = 0;

   int nonvirtual( void );

};

storable::storable  ( void

) { stuff = 0;                       }

void

storable::print( void ) { /* материал для отладки print */ }

void

storable::virtf( void ) { /* делай что-нибудь */           }

int  storable::nonvirtual( void ) {                             }

Лежащее в основе определение класса (сгенерированное компилятором) может выглядеть подобно этому:

int _storable__print          ( storable *this ) { /* ... */ }

int _storable__virtf          ( storable *this ) { /* ... */ }

int _storable__nonvirtual     ( storable *this ) { /* ... */ }

typedef void

(*_vtab[])(...); // массив указателей на функции

_vtab _storable__vtab

{

   _storable__print,

   _storable__virtf,

   NULL             // метка-заполнитель для функции сравнения

};

typedef struct

storable

{

   _storable__vtab *_vtable;

   int stuff;

}

storable;

_storable__ctor( void )      // конструктор

{

   _vtable = _storable__vtable; // Эту строку добавляет




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