本篇主要是写c++三大特性:封装、继承、多态的知识点,其中封装是为了实现代码模块化;继承是为了实现代码复用;多态是为了实现接口重用。下面分别详细说这三部分。
-
封装(数据、接口、实现)
-
继承(public、protected、private)
1、类在实现过程中把数据的定义和操作放在类的内部,对外仅提供接口,这样将实现细节隐藏在类内部,对外不可见;
通过子类继承父类已有的特性,在无需重复实现同样功能的前提下扩展自身的新功能, 解决了代码复用的问题,这种模式大大提高了开发效率。
-
多态(静态多态、动态多态)
对于多态来说,首先要理解重载和覆盖(重写)的区别。
下面来介绍静态多态和动态多态。
静态多态:通过重载实现的,包括函数重载、运算符重载等;
动态多态:通过虚函数实现(有普通虚函数、纯虚函数,纯虚函数是为了父类定义接口,子类继承后提供具体的实现),需要virtual关键字,运行时通过基类指针指向派生类对象。
-
虚函数表:存在常量存储区,属于只读存储段,即代码段,包括了类中所有虚函数的地址,按照声明的顺序排列。
-
虚函数指针:每个类对象都有一个虚函数指针,当利用一个基类的指针绑定基类或派生类对象时,程序运行时调用某个虚函数成员,会根据对象的类型去初始化该虚函数指针,实现动态绑定。
对于拥有虚函数类而定义的对象来说,每个对象都会拥有虚函数指针,但是会同一个虚函数表。当生成对象时,会在对象起始位置放置一个虚表指针,用来调用虚函数表中的虚函数。
虚函数对象模型
接下来我会分析虚函数对象模型,如果面试问到虚函数的话可以说这部分,如有疑问可以看《深度探索C++对象模型》这本书,我也是主要从这本书里面总结的,有专门的一章写这个,下文图片主要是也是从本书截图。
虚表指针(vptr)的位置(头部或尾端):
-
放置尾端的好处:可以保留基类的对象布局
-
放在头部的好处:在多重继承下,通过指向类成员的指针调用虚函数会带来一些帮助。否则,对于放在尾端的话需要计算offset。但是他也丧失了c语言的兼容性。
-
单一继承:在子类的内存空间中,首先会继承父类的虚函数表,若在子类中定义了不存在的虚函数,则会放置在父类虚函数的后面。
-
多重继承:在子类中的每个父类都有虚函数表,因此会有多个虚函数指针,子类中定义不存在的虚函数则放在第一个父类的表中。
单一继承和多重继承
虚函数带来的问题:1、明显的增加了空间负担;2、打断了与c程序间的链接性。
1、若单一继承且无虚函数,其内存布局如下,根据声明顺序存放。
2、若单一继承且含有虚函数,其中虚函数指针可放在头部或尾部,由编译器决定,一般是放在头部。
3、多重继承
4、虚继承
5、虚继承下的继承类中带有虚函数(可不看,面试回答前4个就可以了)
全部评论
(1) 回帖