下面的几个问题实际上是准备找工作过程中遇到的,但是一直迟迟没有做出相应的思考。
一.首先这里要提出一个问题,怎样才能获取虚函数表指针的存储地址、虚函数表指针的值、虚函数表的存储地址以及虚函数表中存储的虚函数地址?
例如,有如下的代码段:
class Base {
public:
virtual int fun1() {
std::cout << "Base::fun1()" << std::endl;
}
virtual int fun2() {
std::cout << "Base::fun2()" << std::endl;
}
virtual int fun3() {
std::cout << "Base::fun3()" << std::endl;
}
private:
};
int main(int argc, char* argv[]) {
Base b;
//获取类对象b的地址,实际上也是虚函数表指针vptr的地址,
//因为vptr位于对象b的起始位置。
std::cout << &b << std::endl;
//但是怎样获取vptr的内容?vptr为指针类型,4bytes。
std::cout << *(int*)&b << std::endl;
//获取vptr的内容,相当于获取虚函数表的首地址。
//怎样获取虚函数表中第一个函数的地址?
//即是虚函数int fun1()的地址。
std::cout << *(int*)*(int*)&b << std::endl;
//那么虚函数int fun2()的地址也就得到。
std::cout << *((int*)*(int*)&b + 1) << std::endl;
return 0;
}
虽然在上述代码中给出了所提问题的答案,但是要问自己几个问题?除了对于虚函数的
基本理解外,实质是关于指针的问题。
- vptr的存储地址是?vptr位于类对象b的内存空间起始处,因此存储vptr的内存地址和&b相同,但是不能说存储vptr的内存地址就是&b。二者类型不同,需要强制类型转换,vptr的存储地址应该是(int*)&b。
- 虚函数表中存储虚函数地址的地址是?有了vptr的值,我们很快能得到该问题的答案:*(int*)&b。因为vptr指向虚函数表的首地址。
- 虚函数表中存储首个虚函数的地址是?虚函数的地址在虚函数表中是按照类中声明的顺序存放的,首个虚函数的地址是:*(int*)*(int*)&b,这里也用到了强制类型转换。