求教一些关于虚函数的有关问题
求教一些关于虚函数的问题。
首先,我知道A有一个VPTR,指向它的虚函数表。
我的问题是,对于A的所有对象,例如A a1, A a2,这个a1和a2的VPTR是否和A的VPTR是同一个值,指向同一个虚函数表?还是对于每个对象,都有一个虚函数表?
问题2,Thinking in C++上有这么一句话:“如果一个函数在基类中被声明为virtual,则在所有的派生类中它都是virtual”,是什么意思呢?
如果我这样实现B,
那么B是派生类,但B中的fa不是virtual啊。
问题3,对于每一个类来说只有一个VPTR,但对于C,
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
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; }