求教一些关于虚函数的有关问题

求教一些关于虚函数的问题。
C/C++ code

class A
{
public:
    virtual void fa() { cout << "A::f" << endl; };
};



首先,我知道A有一个VPTR,指向它的虚函数表。

我的问题是,对于A的所有对象,例如A a1, A a2,这个a1和a2的VPTR是否和A的VPTR是同一个值,指向同一个虚函数表?还是对于每个对象,都有一个虚函数表?

问题2,Thinking in C++上有这么一句话:“如果一个函数在基类中被声明为virtual,则在所有的派生类中它都是virtual”,是什么意思呢?

如果我这样实现B,

C/C++ code

class B : public A
{
public:
    void fa() { cout << "B::f" << endl; };
};



那么B是派生类,但B中的fa不是virtual啊。

问题3,对于每一个类来说只有一个VPTR,但对于C,

C/C++ code

class C : public A
{
public:
    void fa() { cout << "C::f" << endl; };

    virtual fc() { cout << "C::f" << endl; };
};



C有一个VPTR指向它自己的虚函数,但它是怎么找到A中的虚函数表的?是否表示C中还存了一个A的VPTR,可是sizeof(C)为4,表示只有一个VPTR,不太理解。

------解决方案--------------------
我的问题是,对于A的所有对象,例如A a1, A a2,这个a1和a2的VPTR是否和A的VPTR是同一个值,指向同一个虚函数表?还是对于每个对象,都有一个虚函数表?

a1,a2的vptr指向同一个表

问题2,Thinking in C++上有这么一句话:“如果一个函数在基类中被声明为virtual,则在所有的派生类中它都是virtual”,是什么意思呢?

就是说派生类同名的 参数相同的函数默认也是virtual的
------解决方案--------------------
C有一个VPTR指向它自己的虚函数,但它是怎么找到A中的虚函数表的?是否表示C中还存了一个A的VPTR,可是sizeof(C)为4,表示只有一个VPTR,不太理解。

c有一个自己的虚函数表 C类型的对象里面的vptr只会指向C自己的虚函数表。
------解决方案--------------------
1. 两个对象的虚函数表的地址应该是不一样的,但是两个对象对应的虚函数地址(及虚函数表中某项所指向的内容)是一样的。参考下面的代码:
C/C++ code

#include <iostream>
using namespace std;

class A
{
public:
    virtual void fa()
    { 
        cout << "A::f" << endl; 
    }
};

// 定义一个函数指针类型
typedef void (*fun)();

// 获取一个对象中的虚函数指针
fun getVirtualFunction(A* obj, unsigned long offset)
{
    // 1. obj就是类A的对象地址,而vfptr总是在一个对象内存布局的最前面,因此obj其实也就是vfptr的开始;
    // 2. 在32-bit的操作系统中,地址空间也是32-bit的,我们知道long是4Bytes,因此(unsigned long*)obj就是vfptr
    //    指针(即包括obj及其后面3个Bytes的内容,unsigned long*从本质上说,就是限定包括obj及其后面3个Bytes的
    //    内容作为vfptr指针);
    // 3. *(unsigned long*)obj,就是vfptr指针中的内容,其中前4Bytes也就是virtual table的起始地址;
    // 4. (unsigned long *)(*(unsigned long*)obj)取得virtual table的4Bytes地址,也就是虚函数表中第一项,它也
    //    是一个指针,这个指针指向第一个虚函数的地址,也就是说该指针的内容为第一个虚函数的指针;如果offset = 1,
    //    那么(unsigned long *)(*(unsigned long*)obj) + offset就是虚函数表中第二项,它是一个指向第二个虚函数地
    //    址的指针,依此类推;
    unsigned long* vtbl = (unsigned long *)(*(unsigned long*)obj) + offset;
    // 5. 承4,如果vtbl是虚函数表中第一项,那么*(vtbl)就是第一个虚函数的指针,通过(fun)转化成为一个无参数,返回
    //    值类型为void的函数指针,以此类推。
    fun p = (fun) *(vtbl);
    return p;
}

int main(int argc, char** argv)
{
    A a1;
    A a2;

    cout << &a1 << endl;    // a1的虚函数表的地址,其实也就是a1的this指针
    cout << &a2 << endl;    // a2的虚函数表的地址,其实也就是a2的this指针
    cout << getVirtualFunction(&a1, 0) << endl;        // 对象a1的虚函数fa的指针
    cout << getVirtualFunction(&a2, 0) << endl;     // 对象a2的虚函数fa的指针

    return 0;
}