C++ 虚函数 单一继承 多重继承 单一虚继承 菱形虚继承 的简洁总结

最近在搞类设计的时候,突然发现这些知识都淡忘了,遂立即展开学习~搜索很多网上的资料,算是看明白了。网上有很多牛B的帖子,其中有一个人小总结了一下这些贴:【转】虚继承虚函数总结小贴  ;

文章中提到了几个很好的博客总结,都不错。我下面的文章是按照自己的理解,加上对他人精华东西的萃取,弄的一个较为整洁的贴。恩算是原创~所有引用都在上面的那个【转】链接博客中,详细的可以去拜读原文。   


虚函数

  • 所谓虚函数,从其功能上来看是采用虚调用的方式;当子类重新定义其父类的虚函数以后,父类指针根据付给他的不同子类指针,动态地调用属于子类的该函数;
  • 假如一个类有虚函数,则该类会因为维护该虚函数,而额外产生一个指针vptr,该指针指向一个虚表,虚表中保存了该类所有的虚函数地址;
    • ---说到这,顺便补充下:在类中,非静态非虚函数,与其他函数一样,其不占用类对象的内存空间,是存储在代码段中的;
    • ---当类对象调用该成员函数时候,与调用普通函数一样,到对应代码段去调用,不同的是会隐式的提供一个参数:this指向该调用者,就是传说中的this指针;
  • 虚函数被继承时,如果子类有同名函数,则在虚表中会覆盖之,如果没有则保存父类的版本;
  • 它,就是为了多态而生滴!


单一继承 (C:B | B : A)

  • 虚函数表在内存中的位置,处在最前面;而成员变量则根据其继承和声明的顺序依次排在后面;
  • 被子类覆盖的虚函数,在表中得到了覆盖更新(在内存中只保留同名虚函数的最下级一个副本c的);


多重继承A ( C : B , A )

  • 每一个父类的虚表在子类中都会保存一份副本,也就是C有三个虚表;
  • 子类自己的虚成员函数被放到了第一个父类的虚表中去了;
  • 内存中,父类的布局按照声明顺序排列;
  • 每个父类的虚函数(如果有被C类override的话,即使是大家都有f(),而c也有虚函数f)都被覆盖为子类的虚函数;
  • 也即不同的父类指针,被子类赋值后,还都调用同一个(子类的)虚函数,因为都被覆盖了;


多重继承B-重复继承 ( D : B , C | B:A | C : A)

  • 首先B和C里面都会保存A的一套副本,这个分别都是是简单的单一继承
  • 而后到D分别去继承B和C的时候,回到了上一小节的多重继承A,D中会完整的保存B和C的信息,而B和C中又各有一份A,所以在D中会存在两份A信息;
  • 其实这个情况就是 先单一继承,再多重继承A的结合体!考虑下看~
  • 两份的话怎么搞呢?那用D调用到底调用的是A里面的哪一个呢?所以这个问题,想解决,就得用到下面一节的,虚继承!虚继承就是解决了这个问题~它将多重继承来的同一个父类只在子类中保存一个实体,这个实体保留哪个,是按照继承时候的生命顺序定的,一般是保存最后声明的那个C的;



虚继承

  • B : virtual public A;这就完成了一个简单的虚继承;
  • 单一的虚继承,基本和单一继承没有太大区别,关键是形成菱形结构的多重继承,看看它是怎么去除那多出来的一份A的;见下节;
  • 要好好研究 虚继承好帖 这个文章。

菱形继承 ( D:B,C | B:virtual A | C:virtual A )

  • 在多重继承B那节说过,这种继承会让D中保存了两份A的内容。那通过菱形虚继承以后,会怎么样呢?我们简单的说一下好了
  • virtual base class table 和 Bjarne办法~
  • 前者是无论有多少继承基类,那都放在一个Table中,在子类D中只有一个指针,它指向这个虚基类表,这样的话就避免了重复(这样子类有两个指针,一个虚表指针,一个虚基类表指针)
  • 后者呢,是在虚函数表中放置基类的offset偏移。
  • 具体的还是参考 虚继承好帖 里的详细描述吧。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值