虚函数(继承,多态中的理解,vptr和vtbl)

继承和虚函数

对象模型:关于vptr和vtbl

侯捷大神的课程(讲的巨TM好!有一定难度,但是很精彩,c++学习的小伙伴一定要看!)

 

我们知道,如果子类继承了父类,那么子类是能够继承父类的所有数据的(如果继承限制允许)

继承中使用虚函数:

    不是虚函数:这样的函数在父类中已经设计好,而且是不想要子类继承的

       不纯虚函数:这样的函数父类已经实现了,子类在继承父类此函数的时候,能够根据自己的需求使用或者完善这个功能

       纯虚函数:所有的功能父类已经实现了,让子类继承这个功能(也是能修改的)

 

虚函数最经典的用法:

很巧妙的框架:

因为有些函数子类没法实现(或者父类所设计的功能是拿来卖钱,卖给子类),所以就继承父类,通过子类的对象来调用父类的函数 myDoc.OnFileOpen();

    让子类定义所继承的父类,完成功能,也就是父类提出了功能,将其延缓了(几年后再用等),子类在用的时候在去定义它,这个方法就是(Template Method)

    下面举一个栗子:    

 

 

 

某厂面试题:

    很经典的pFun = ( Fun )*( ( int* ) * ( int* )( &b ) + i )

https://zhidao.baidu.com/question/372005299.html
poorcowboy回答:

typedef void( *Fun )( void ); //把Fun定义为一个没有参数,返回void类型的du函数指针

*( ( int* ) * ( int* )( &b ) + i )这一段,

(int*)*相当于没有进行zhi任何操作,所以等同于

*( ( int* )( &b ) + i )

这里先取b的地址dao,然后把地址转换成int*,之后+i是指针算术,也就是在b的地址上加一个int的长度,最后最前面的*是解指针,座椅这段最后返回的是“b的地址+i个int长度的值”

最前面的(Fun)是强制把“b的地址+i个int长度的值”转换为一个“没有参数,返回void类型的函数指针”,所以pFun就是一个函数指针,其指向的位置从一开始的b的地址,每次循环加一个int的长度

然后我们开看,b的地址,b是一个B类型,B类型的第一个函数是g(),而第一次循环pFun的地址就是b的地址,b又没有属性(私有或共有变量)所以b的地址就是b中第一个函数g的地址,所以第一次循环的pFun()相当于调用B::g

( Fun )*( ( int* ) * ( int* )( &b ) + i ); 这里*( ( int* ) * ( int* )( &b ) + i )最前面的*是对上面的结果进行解指针,也就取把b的地址+i个int长度的这个地址的值,并把它转换为Fun类型,也就是一个没有参数,返回void类型的函数指针,所以最后得到的就是一个函数指针。这个指针所指向的地址就是

然后我们来看循环,循环中3次pFun变量分别被赋了3次值,每次都是一个函数指针

由于B类型中有virtual函数,所以b的地址指向的是b的vtbl(如果你不知道这个,你面试就没戏了),vtbl可以看作一个保存了函数指针的数组,每个元素就是一个int长度,在vtbl中B::g,A::f,B::h是按照如上顺序排列的,所以第一次循环指向B::g,那么后两次就指向A::f和B::h了

至于为什么是按照这样的顺序排列的,是因为其声明顺序,首先是父类的virtual函数按照其生命顺序放入vtbl中,然后是子类的放进去,所以其顺序是:A::h,A::f(这是父类的声明顺序)子类中只有B::H是新声明的,所以顺序是A::g,A::f,B::h。

又因为b的类型是b,你知道什么事多态和动态绑定,就明白第一个调用的为什么是B::g而不是A::g了。

 

关于C++ 对象的内存布局

haoel大神的文章:https://blog.csdn.net/haoel/article/details/3081328

 

上边说的就是虚函数中的vptr和vtbl,以及继承和多态的使用

 

对象模型:关于vptr 和vtbl

 

通过指针p 调用C::vfunc1()

编译器看到一个调用的动作,在过去c的时代,是把它编译成一个特定的语法,call调用***一个地址,你要调用哪一个函数,编译器就跳到一个地方去,将来在return 回来,这就是静态绑定,精准到地址。

现在通过指针调用虚函数的时候,是面向对象设计的关键,避免繁琐的类型判断动态绑定(虚机制),逻辑意义就是走的vptr->vtbl->fun()  

(条件:

通过指针调用,

指针p需要向上转型,子类->父类,即new的对象是子类,声明时是父类,保证安全

必须要有虚函数)

虚函数的指一种用法就是多态,指针指向不同的类型list<A*>mylist

解析成c:  (*(p->vptr)[n])(p);

          (*p->vptr[n])(p);

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值