Я недавно был на интервью относительно положения, где C/C++ является основным языком, и во время одного вопроса мне сказали, что возможно использовать vtable для определения, какой класс в иерархии указатель базы на самом деле хранит.
Таким образом, если, например, Вы имеете
class A
{
public:
A() {}
virtual ~A() {}
virtual void method1() {}
};
class B : public A
{
public:
B() {}
virtual ~B() {}
virtual void method1() {}
};
и Вы инстанцируете A * pFoo = new B()
, действительно возможно использовать vtable, чтобы определить, содержит ли pFoo указатель на экземпляр A или B?
Это, очевидно, зависит от реализации, но в большинстве реализаций представление объекта класса в памяти A
или B
начнется с указателя на vtable. Вы можете посмотреть на этот указатель vtable, сравнить его с указателями vtable для объектов, которые, как вы знаете, относятся к классу A
или B
, и таким образом определить класс объекта.
Чтобы проиллюстрировать (конечно, это совсем не хороший стиль):
A *pFoo=new B(); // pointer to object of unknown class (either A or B)
A a; // Object known to be of class A
B b; // Object known to be of class B
void *vptrA=*((void **)&a); // Pointer to vtable of class A
void *vptrB=*((void **)&b); // Pointer to vtable of class B
void *vptrFoo=*((void **)pFoo); // Pointer to vtable of unknown object
if(vptrFoo==vptrA)
printf("Class A\n");
else
printf("Class B\n");
Важно: это только иллюстрация того, как работает большинство реализаций; Помимо того, что этот метод зависит от реализации, он не работает при множественном наследовании. Вы не должны никогда делать что-либо подобное в производственном коде; используйте вместо этого RTTI.
Вы можете получить доступ к vpointer и даже можете вызвать любой виртуальный метод в классе через vpointer. Но помните, что это ЗЛО.
Пример :
class A
{
public:
void f1()
{
cout<<"bbb"<<endl;;
}
virtual void f2()
{
cout<<"ccc"<<endl;;
}
virtual void f3()
{
cout<<"ddd"<<endl;;
}
};
и вызов в main
A a;
typedef void (__thiscall* foo)();
(*(foo)((void**)(((void**)(&a))[0]))[1])();
Он получит доступ к vpointer, затем перейдет по индексу и выполнит второй метод в vTable, который является f3().
Также обратите внимание на использование RTTI, как уже было предложено.
Да, это вполне возможно сделать - использовать dynamic_cast. Это довольно дерьмовый вопрос - немного лучше было бы спросить "Как реализован dynamic_cast?", но если бы мне задали такой вопрос на собеседовании, я бы задумался о сообразительности интервьюера. Быть хорошим или даже отличным программистом на C++ не зависит от знания таких придирчивых деталей реализации, как эти, но, конечно, это легкие вопросы для второкурсников.