Виртуальные базовые классы с виртуальными функциями

При наличии виртуальных базовых классов построение таблиц для вызовов виртуальных функций становится более сложным. Рассмотрим следующие объявления:

class W { public: virtual void f(); virtual void g(); virtual void h(); virtual void k();};class MW : public virtual W { public: void g();};class BW : public virtual W { public: void f();};class BMW : public BW, public MW, public virtual W { public: void h();};

Отношение наследования для этого примера может быть изображено в виде ациклического графа таким образом:


Рис. 9.22.

Функции-члены класса BMW могут использоваться, например, так:

void g(BMW¤pbmw){pbmw ! f(); == вызывает BW :: f()pbmw ! g(); == вызывает MW :: g()pbmw ! h(); == вызывает BMW :: h()}

Рассмотрим теперь следующий вызов виртуальной функции f():

void h(BMW*pbmw) {MW*pmw = pbmw; pmw ! f(); == вызывает BW :: f(); потому, что // pbmw указывает на BMW, для которого f бер"тся изBW! }

Виртуальный вызов функции по одному пути в структуре наследования может привести к обращению к функции, переопределенной на другом пути.

Структура объектов класса BMW и его таблиц виртуальных функций vtbl могут выглядеть следующим образом:


Рис. 9.23.

Виртуальной функции должен быть передан указатель this на объект класса, в котором эта функция описана. Поэтому следует хранить смещение для каждого указателя функции из vtbl. Когда объект размещен в памяти так, как это изображено выше, смещение, хранимое с указателем виртуальной функции, исчисляется вычитанием смещения класса, для которого эта таблицаvtbl создана, из смещения класса, поставляющего эту функцию. Рассмотрим пример:

void callvirt(w*pw){ pw ! f();}main (){ callvirt(new BMW);}

В функции main вызов callvirt с указателем на BMW требует приведения к указателю на W, поскольку функция callvirtожидает параметр типа W*. Так как функция callvirt вызывает f() (через указатель на BMW, преобразованный к указателю наW ), будет использована таблица vtbl класса W (в BMW ), где указано, что экземпляром виртуальной функции f(), которую нужно вызвать, является BW :: f(). Чтобы передать функции BW :: f() указатель this на BW, указатель pw должен быть вновь приведен к указателю на BMW (вычитанием смещения для W ), а затем к указателю на BW (добавлением смещения BW в объекте BMW ). Значение смещения BW в объекте BMW минус смещение W в объекте BMW и есть смещение, хранимое в строке таблицы vtbl для w в BMW для функции BW :: f().








Дата добавления: 2016-06-13; просмотров: 870;


Поиск по сайту:

При помощи поиска вы сможете найти нужную вам информацию.

Поделитесь с друзьями:

Если вам перенёс пользу информационный материал, или помог в учебе – поделитесь этим сайтом с друзьями и знакомыми.
helpiks.org - Хелпикс.Орг - 2014-2024 год. Материал сайта представляется для ознакомительного и учебного использования. | Поддержка
Генерация страницы за: 0.004 сек.