我最近正在接受采访,其中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实例的指针?
答案 0 :(得分:11)
这显然取决于实现,但在大多数实现中,类A
或B
的对象的内存中表示将以指向vtable的指针开始。您可以查看此vtable指针,将其与您知道属于类A
或B
的对象的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。
答案 1 :(得分:3)
是的,很有可能 - 使用dynamic_cast。这是一个非常糟糕的问题 - 稍微好一点的可能是“如何实现dynamic_cast?”但是如果在面试中被问到,我真的不得不怀疑面试官的情况。作为一个优秀的,甚至是伟大的C ++程序员,并不依赖于知道这样的挑剔实现细节,但这些对于第二个评估者来说当然是一个简单的问题。
答案 2 :(得分:2)
答案 3 :(得分:1)
您可以访问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。