7

我最近接受了一个 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

4 回答 4

12

这显然是依赖于实现的,但在大多数实现中,类对象的内存表示AB将以指向 vtable 的指针开始。您可以查看此 vtable 指针,将其与您知道属于AB类的对象的 vtable 指针进行比较,并以这种方式确定对象的类。

举例说明(当然,这绝不是好的风格):

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。

于 2010-06-09T14:33:03.193 回答
4

是的,这很有可能 - 使用 dynamic_cast。这是一个非常糟糕的问题——一个稍微好一点的问题可能是“dynamic_cast 是如何实现的?” 但真的,如果在面试中被问到,我不得不怀疑面试官的诺言。作为一个优秀的,甚至是优秀的 C++ 程序员,并不依赖于了解像这样挑剔的实现细节,但是对于二流的人来说,这些当然是很容易提出的问题。

于 2010-06-09T15:29:02.683 回答
2

检查typeid() 函数

于 2010-06-09T15:43:36.420 回答
1

您可以访问 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。

于 2010-06-09T14:44:19.360 回答