Какова структура виртуальных таблиц в C++?
Например, у меня есть два "intefaces" и тип класса:
class IPlugin
{
public:
virtual void Load(void) = 0;
virtual void Free(void) = 0;
};
class IFoo
{
public:
virtual void Foo(void) = 0;
};
class Tester: public IPlugin, public IFoo
{
public:
Tester() {};
~Tester() {};
virtual void Load()
{
// Some code here
}
virtual void Free()
{
// Some code here
}
virtual void Foo(void)
{
// Some code here
}
};
Какую структуру на самом деле имеет vtab, например, типа Tester
? И как бы dynamic_cast
оператор действовать (я имею в виду, как dynamic_cast
оператор будет проверять vtab на предмет правильного преобразования ссылочного типа) в выражении:
Tester* t = new Tester();
IPlugin* plg = dynamic_cast<IPlugin*>(t);
IFoo* f = dynamic_cast<IFoo*>(plg);
Заранее спасибо!
4 ответа
Виртуальные таблицы в C++ - это деталь реализации. Одна из возможных реализаций показана на диаграмме ниже.
Существует два экземпляра класса (A и B). Каждый экземпляр имеет два указателя vtbl, а vtbl содержит указатели на реальный код.
В вашем примере нет данных экземпляра, но я для иллюстрации предположил, что каждый класс содержит некоторые данные экземпляра.
Когда указатель на Tester
приведен к указателю на IFoo
указатель отрегулирован, как показано на рисунке. Вместо указания на начало данных экземпляра он указывает на IFoo
часть данных экземпляра.
Приятно то, что вызывающий абонент использует IFoo
Указатель не имеет никаких знаний о данных, окружающих IFoo
часть класса. То же самое можно сказать и о вызывающем абоненте, использующем IPlugin
указатель. Этот указатель указывает на начало данных экземпляра, на которые также указывает Tester
указатель, но только вызывающий Tester
Указатель знает всю структуру данных экземпляра.
С помощью dynamic_cast
требуется RTTI (информация о типе времени выполнения), которого нет на диаграмме. Vtbl будет содержать дополнительную информацию о типе, которая дает право голоса IFoo
указатель на экземпляр Tester
позволяет коду во время выполнения обнаружить фактический тип объекта, на который указывает указатель, и использовать его для понижения указателя.
В ИСО / МЭК 14882 Второе издание 2003-10-15 не существует таких терминов, как vptr, виртуальная таблица, поэтому он полностью зависит от разработчиков компиляторов.
Информация о импл. в Microsoft Visual C++: http://www.openrce.org/articles/files/jangrayhood.pdf
Статья о импл. виртуальные таблицы в g ++: http://phpcompiler.org/articles/virtualinheritance.html
Какую структуру на самом деле имеет vtab, например, типа Tester?
Механизм виртуальной диспетчеризации определяется реализацией. vtable и vptr не требуются стандартом C++, и эти знания даже не требуются программистам для программирования на C++, потому что вы не можете получить доступ к виртуальной таблице (даже если ваш компилятор реализует это); он генерируется компилятором и добавляется в ваш код, как будто он многое делает с вашим кодом, прежде чем преобразует его в машинный код.
Tester* t = new Tester();
IPlugin* plg = dynamic_cast<IPlugin*>(t);
IFoo* f = dynamic_cast<IFoo*>(plg);
Вот dynamic_cast
не нужно во второй строке. Достаточно следующего:
Tester* t = new Tester();
IPlugin* plg = t; //upcast - dynamic_cast not needed
IFoo* f=dynamic_cast<IFoo*>(plg); //horizontal-cast - dynamic_cast needed
dynamic_cast
не нужен в upcast; он нужен только в нижнем и горизонтальном режимах.
Tester* tester1 = dynamic_cast<Tester*>(plg); //downcast - dynamic_cast needed
Tester* tester2 = dynamic_cast<Tester*>(f); //downcast - dynamic_cast needed
Виртуальный механизм (Virtual Pointer & Virtual Table) не определяется стандартом C++. Компилятору не нужно реализовывать механизм по своему выбору. Это деталь реализации компилятора. Учитывая это, детали того, как компилятор будет реализовывать виртуальный механизм, абстрагируются от пользователя. Важно только то поведение, которое ожидается от виртуального механизма.
В твоем случае:
Tester* t = new Tester();
IPlugin* plg = dynamic_cast<IPlugin*>(t);
IFoo* f = dynamic_cast<IFoo*>(plg);
plg
& f
оба будут указывать на действительный объект их соответствующих типов, потому что t
Это происходит от них обоих.
Конечно, это не отвечает на конкретный вопрос, который вы задали, а просто хотел прояснить детали виртуального механизма, являющегося подробностью реализации компиляторов.