Как использовать vtable для определения типа класса - PullRequest
7 голосов
/ 09 июня 2010

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

Ответы [ 4 ]

11 голосов
/ 09 июня 2010

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

3 голосов
/ 09 июня 2010

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

2 голосов
/ 09 июня 2010

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

1 голос
/ 09 июня 2010

Вы можете получить доступ к vpointer и даже можете вызвать любой виртуальный метод в классе через vpointer. Но помни, что это ЗЛО.

Пример:

class A
{
public:
    void f1()
    {
        cout<<"bbb"<<endl;;
    }
    virtual void f2()
    {
        cout<<"ccc"<<endl;;
    }
    virtual void f3()
    {
        cout<<"ddd"<<endl;;
    }
};

и позвоните на главную

A a;

typedef void (__thiscall* foo)();
(*(foo)((void**)(((void**)(&a))[0]))[1])();

Получит доступ к vpointer, затем пойдет по индексу и выполнит второй метод в vTable, который называется f3 ().

Также обратите внимание на использование RTTI, как уже предлагалось.

...