Как использовать vtable для определения типа класса

Я недавно был на интервью относительно положения, где 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?

7
задан Martin B 9 June 2010 в 14:38
поделиться

4 ответа

Это, очевидно, зависит от реализации, но в большинстве реализаций представление объекта класса в памяти 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.

11
ответ дан 6 December 2019 в 11:46
поделиться

Вы можете получить доступ к 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, как уже было предложено.

1
ответ дан 6 December 2019 в 11:46
поделиться

Да, это вполне возможно сделать - использовать dynamic_cast. Это довольно дерьмовый вопрос - немного лучше было бы спросить "Как реализован dynamic_cast?", но если бы мне задали такой вопрос на собеседовании, я бы задумался о сообразительности интервьюера. Быть хорошим или даже отличным программистом на C++ не зависит от знания таких придирчивых деталей реализации, как эти, но, конечно, это легкие вопросы для второкурсников.

3
ответ дан 6 December 2019 в 11:46
поделиться

Проверьте функцию typeid () .

2
ответ дан 6 December 2019 в 11:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: