c++中的虚函数表测试(关于类的动态调用和静态调用)

虚函数表的百度解释如下:

类的虚函数表是一块连续的内存,每个内存单元中记录一个JMP指令的地址

  注意的是,编译器会为每个有虚函数的类创建一个虚函数表,该虚函数表将被该类的所有对象共享。类的每个虚成员占据虚函数表中的一行。如果类中有N个虚函数,那么其虚函数表将有N*4字节的大小。

 

一个类只要有虚函数,其就会有有一个虚函数表指针,通过指针,编译器可以找到对应的虚函数地址。具体说明见下面的网址

http://apps.hi.baidu.com/share/detail/10397448

 

此处我想通过一个实验来加强对编译器使用虚函数表的理解。讨论帖见下面的地址

http://topic.csdn.net/u/20100714/14/1bf1685b-eeed-4562-9836-7291a61f8315.html?seed=1792954863&r=66962110#r_66962110

 

我设计两个类,一个基类和它的派生类,两个类都只有一个虚函数。在百度上查到“类的虚函数表是一块连续的内存,每个内存单元中记录一个JMP指令的地址”。因此我想,如果我将派生类对象覆盖了基类对象,是否会把基类的虚函数表指针更改呢?

测试的代码如下:
int *pa; int *pb; class A { public: virtual print() { pa=(int *)this; cout<<"A::print:"<<pa<<" "<<*pa<<" "<<*((int *)(*pa))<<endl; } }; class B:public A { public: virtual print() { pb=(int *)this; cout<<"B::print:"<<pb<<" "<<*pb<<" "<<*((int *)(*pb))<<endl; } }; int main() { B b; b.print(); A a; a.print(); memcpy(&a,&b,sizeof(a)); a.print(); return 0; }

 

有兴趣的可以运行一下。
输出显示a的this指针保存的内容的确发生了变化,但是其仍能寻找的a的print函数。这让我对虚函数表指针产生了疑惑,这个指针明明指向的是b的虚函数表,为啥没有调用b的print函数呢?编译器是如何做到这一点的?

 

后来使用A *p=&a;p->print();发现此时调用的是B的打印函数。

 

关于这个疑惑,一个牛人(飞雪)的解释是,多态的条件不满足,意思是只有指针或引用才能产生多态,也就是说p是指针,编译器会进行多态性检测(检查虚函数表)。而a.print()不是指针或引用,并不满足多态条件,那a.print()编译器是如何查找函数地址的呢?这个问题没有人告诉我,还需要等待。。。

 

经过讨论帖里的回复,终于明白了编译器的调用原则:静态调用和动态调用

 

a.print()   等价于 a.A::print(); 此处是静态调用,因此此时不会经过虚函数表

 

p->print() 等价于 a.B::print();此处是动态调用,因此需要查询虚函数表

 

后来我又做了一个实验加深理解,将B类空间的打印去掉,声明一个C类继承B类,如上述操作后,调用b.print(),我想此处B::print是不存在的,它是否会去找虚函数表呢?证明结果不会,因此静态调用应该是当B类空间找不到时,会到B类的基类中寻找,即b.B::A::print()。只有动态调用才会找虚函数表,而满足动态调用的条件是指针或引用。

你可能感兴趣的:(C++,百度,测试,Class,编译器,2010)