把关于虚函数不清楚的地方小测试了下,记录下来,备忘
测试编译器:mingw32-gcc-3.4.5
struct A{ virtual void f1(){ std::cout<<"A::f1"<<std::endl; } virtual void f2(){ std::cout<<"A::f2"<<std::endl; } void f3(){ std::cout<<"A::f3"<<std::endl; }};struct B:A{ void f1(){ std::cout<<"B::f1"<<std::endl; } virtual void f2(){ std::cout<<"B::f2"<<std::endl; } void f3(int){ std::cout<<"B::f3"<<std::endl; }};void vf_test(){ A a; B b; //now, p1 point to a B instance, "*p1" object's vpointer point to B's vtable A *p1=new B; //ok, p1 is A's pointer, so it calls none virtual function A::f3() p1->f3(); //compile time error, notice that the member functions have the same name as the derived-class's will be rewrite. //so, B::f3(int) hides A::f3() //b.f3(); //calls A::f1() (*p1).A::f1(); //calls B::f1() (*p1).f1(); //calls B::f2() (*p1).f2(); //(A(*p1)).f1() and (A(*p1)).f2() symbols will be linked to A's member function. (A(*p1)).f1(); (A(*p1)).f2(); //but, notice that "*p1" object's vpointer point to B's vtable //so, after type casting, "*p1" object's vpointer looks like already point to A's vtable at runtime //let's take a test about it //A's and B's object only have a vpointer of 4 bytes std::cout<<"size of A is "<<sizeof(A)<<std::endl; std::cout<<"size of B is "<<sizeof(B)<<std::endl; std::cout<<"virtual pointer's value of type A is "<<*(unsigned long*)(&a)<<std::endl; std::cout<<"virtual pointer's value of type B is "<<*(unsigned long*)(&b)<<std::endl; std::cout<<"virtual pointer's value of p1 is "<<*(unsigned long*)p1<<std::endl; std::cout<<"virtual pointer's value of &A(*p1) is "<<*(unsigned long*)(&(A(*p1)))<<std::endl; delete p1;}
output:
A::f3
A::f1
B::f1
B::f2
A::f1
A::f2
size of A is 4
size of B is 4
virtual pointer's value of type A is 4508528
virtual pointer's value of type B is 4508544
virtual pointer's value of p1 is 4508544
virtual pointer's value of &A(*p1) is 4508528
这个测试主要是说明虚表指针的运行时切换问题,关于虚函数与类的作用域的较详细解释可参见《C++ Primer 4th Edition》15.5.4, 特别要注意派生类成员名字屏蔽基类成员名字的问题,这里只摘录其中一段对于继承体系中名字查找的小结供大家参考:
1. 首先确定进行函数调用的对象、引用或指针的静态类型。
2. 在该类中查找函数,如果找不到,就在直接基类中查找,如此循着类的继承链往上找,直到找到该函数或者查找完最后一个类。如果不能在类或其相关基类中找到该名字,则调用是错误的。
3. 一旦找到了该名字,就进行常规类型检查,查看如果给定找到的定义,该函数调用是否合法。
4. 假定函数调用合法,编译器就生产代码。如果函数是虚函数且通过引用或指针调用,则编译器生成代码以确定根据对象的动态类型运行哪个函数版本,否则,编译器生成代码直接调用函数。
原文链接: https://www.cnblogs.com/tnt_vampire/archive/2010/05/15/1736240.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/10889
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!