首页 > c++学习篇(1)
头像
文刀刘+1
编辑于 2020-12-24 09:26
+ 关注

c++学习篇(1)

本人21届年硕士毕业,秋招早已结束,现在特来分享自己在面试中遇到的一些问题及总结的内容。

本篇主要是写c++三大特性:封装、继承、多态的知识点,其中封装是为了实现代码模块化;继承是为了实现代码复用;多态是为了实现接口重用。下面分别详细说这三部分。

    • 封装(数据、接口、实现)

    1、类在实现过程中把数据的定义和操作放在类的内部,对外仅提供接口,这样将实现细节隐藏在类内部,对外不可见;

    2、通过封装可以让使用使用者只关心对象提供的接口,而无需了解具体实现方式,有效地做到了信息隐藏,提高程序的安全性,并且类内部的改动不会影响外部的使用,提高了程序的可维护性


    • 继承(public、protected、private)

    通过子类继承父类已有的特性,在无需重复实现同样功能的前提下扩展自身的新功能, 解决了代码复用的问题,这种模式大大提高了开发效率。

    分类:公有继承、保护继承、私有继承;也可分单一继承和多继承,这部分在动态多态部分讲述。

出现的问题:对于继承来说,会出现菱形继承(定义:多个类继承自同一公共基类,而这些派生类又被同一个类继承),如下图所示,现有基类Base,其中A和B继承自Base,但是C有继承自A,B,因此C产生的对象模型中会出现两份Base,因此会出现数据冗余和二义性的问题。

为了解决数据冗余和二义性的问题,引入了虚继承的概念。如上右图所示,引入virtual关键字。这样在类A和B中只保存了偏移地址,个人理解应该是有虚函数指针,这样将Base中数据保存至一个公共区域,这样解决了数据冗余和二义性的问题。
    • 多态(静态多态、动态多态)

对于多态来说,首先要理解重载和覆盖(重写)的区别。

重载:在同一作用域下,函数名相同,但是函数形参列表不同,包括形参个数、形参类型不同,除此之外,const放在函数名后面也可以实现重载,如下图所示。原理:c++底层的重命名机制,将函数形参类型作为函数名的后缀,这就是为什么C++中写c语言代码需要加“extern”的原因之一。

覆盖(重写):在子类继承父类中,前提是父类中定义了虚函数,若子类中对虚函数进行重新实现,则在子类虚函数表中该虚函数地址改为修改后的虚函数地址。一般需使用virtual关键字,其强调在不同作用域下的子类和父类

下面来介绍静态多态和动态多态

静态多态:通过重载实现的,包括函数重载、运算符重载等;

动态多态:通过虚函数实现(有普通虚函数、纯虚函数,纯虚函数是为了父类定义接口,子类继承后提供具体的实现),需要virtual关键字,运行时通过基类指针指向派生类对象。

    对于拥有虚函数类而定义的对象来说,每个对象都会拥有虚函数指针,但是会同一个虚函数表。当生成对象时,会在对象起始位置放置一个虚表指针,用来调用虚函数表中的虚函数。

    • 虚函数表:存在常量存储区,属于只读存储段,即代码段,包括了类中所有虚函数的地址,按照声明的顺序排列。

    • 虚函数指针:每个类对象都有一个虚函数指针,当利用一个基类的指针绑定基类或派生类对象时,程序运行时调用某个虚函数成员,会根据对象的类型去初始化该虚函数指针,实现动态绑定。


    虚函数对象模型


接下来我会分析虚函数对象模型,如果面试问到虚函数的话可以说这部分,如有疑问可以看《深度探索C++对象模型》这本书,我也是主要从这本书里面总结的,有专门的一章写这个,下文图片主要是也是从本书截图。

虚表指针(vptr)的位置(头部或尾端):

    • 放置尾端的好处:可以保留基类的对象布局

    • 放在头部的好处:在多重继承下,通过指向类成员的指针调用虚函数会带来一些帮助。否则,对于放在尾端的话需要计算offset。但是他也丧失了c语言的兼容性。

    单一继承和多重继承

    • 单一继承:在子类的内存空间中,首先会继承父类的虚函数表,若在子类中定义了不存在的虚函数,则会放置在父类虚函数的后面

    • 多重继承:在子类中的每个父类都有虚函数表,因此会有多个虚函数指针子类中定义不存在的虚函数则放在第一个父类的表中

    虚函数带来的问题:1、明显的增加了空间负担;2、打断了与c程序间的链接性。


1、若单一继承且无虚函数,其内存布局如下,根据声明顺序存放。

2、若单一继承且含有虚函数,其中虚函数指针可放在头部尾部,由编译器决定,一般是放在头部

3、多重继承

4、虚继承


5、虚继承下的继承类中带有虚函数(可不看,面试回答前4个就可以了)



总结:在面试过程中,对于c++三大特性方面问的其实挺多的,但是万变不离其宗,回答问题要找到自己的亮点,比如说面试官问c++的多态特性,那么可以说静态多态实现原理(重载定义和原理:重命名机制等等)、动态多态实现原理(虚函数)、分析单一继承和多继承下的内存模型、虚函数指针在头部和尾端的优劣等等。如果想提升自己的竞争力,一定要去看底层原理或者源码,多总结问题的答案,如果有疑问的话,可以去掘金、CSDN、stackflow这样的技术网站找答案

更多精彩请关注公众号“爱折腾的码农”,二维码见下图。


全部评论

(1) 回帖
加载中...
话题 回帖

推荐话题

相关热帖

近期热帖

近期精华帖

热门推荐