面试总结

面试总结

C++基础

1、深拷贝与浅拷贝
浅拷贝:简单的赋值操作
深拷贝:在堆区重新申请空间进行拷贝
深拷贝的引入是为了解决浅拷贝重复施放堆区内存的问题

2、野指针
指针变量指向非法的内存空间
野指针出现的三种情况:

  1. 指针未初始化
  2. 指针指向的变量被free/delete掉后,指针未置为NULL
  3. 指针所指向的变量超过其生存期

3、四类强制转换

  1. const_cast:const转非const,只能改变运算对象的底层const
  2. dynamic_cast:动态类型转换,用于将基类的指针或引用安全的转换为派生类的指针或引用
  3. static_cast:一切具有明确定义的类型转换,不包含底层const
  4. reinterpret_cast:几乎所有类型转换

4、RTTI(run-time type identification)
运行时类型识别
两个运算符:typeid(用于返回表达式的类型),dynamic_cast

5、指针与数组的区别

指针数组
保存数据的地址保存数据
间接访问数据(先访问指针,用其中地址提取数据进行访问)直接访问数据
通过malloc/free申请释放内存隐式分配和删除
用于动态的数据结构大小固定且类型相同

6、指针和引用的区别

指针引用
指针有自己的一块空间引用只是一个别名
指针可以不初始化,也可以被初始化为空引用必须被初始化,且必须是一个已有对象的引用
指针可以随时更改指向的对象引用一旦初始化就不能指向其他的对象
指针需要被解引用才可以对所指对象进行操作对引用进行修改会改变引用所指向的对象

7、智能指针
动态内存的使用很容易出现问题,确保内存在正确的时间释放是一件很难的事情,如果忘记释放内存,就会导致内存泄漏,如果在尚有指针引用内存时释放,又会产生野指针。为了更安全的使用动态内存,引入了智能指针来管理动态内存。

  1. shared_ptr:允许多个指针指向同一对象
  2. unique_ptr:独占所指对象
  3. weak_ptr:弱引用,指向shared_ptr所管理的对象,是一个伴随类,不控制所指对象的生命期,它的构造和析构都不会引起引用计数的增减

8、C与C++的区别
①C++是面向对象的编程语言,C是面向过程的结构化编程语言
②C++有封装,继承,多态三大特性
③C++相比于C多了许多类型安全的功能,比如强制类型转换
④C++支持范型编程,类模板,函数模板
一些细节:链接: C与C++的区别

9、内联函数
普通函数调用时是进行控制转移,而内联函数是将函数体嵌入到调用处,适用于规模小,使用频繁的函数,不能有递归,循环体,switch,以代码复制为代价,省去函数调用的开销
内联函数和宏的区别: 宏是在预编译阶段展开,而内联函数是在编译阶段进行处理的。同时,宏作为预处理并不进行类型检查,而inline函数是要进行类型检查的,也就可以称作“更安全的宏”。

10、C++编译过程
预处理-编译-汇编-链接
预处理器先处理各种宏定义,交给编译器编译生成汇编代码,交给汇编器生成二进制文件,最后由链接器将一个个目标文件链接成一个可执行的程序。

11、空类对象sizeof为1
编译器为了使这个类的实体在内存中有一个独一无二的地址,往空类里加了一个隐含的字节char

虚函数 类空间占用大小

12、构造函数不能是虚函数

A virtual call is a mechanism to get work done given partialinformation. In particular, “virtual” allows us to call afunction knowing only an interfaces and not the exact type of theobject. To create an object you need complete information. Inparticular, you need to know the exact type of what you want tocreate. Consequently, a “call to a constructor” cannot be virtual.
出处:Stroustrup: C++ Style and Technique FAQ

虚函数调用是一种在给出部分信息的情况下完成工作的机制。 特别是,虚函数使我们可以调用仅知道接口而不知道对象确切类型的函数。 要创建对象,您需要完整的信息。 特别是,您需要知道要创建的确切类型。 因此,“对构造函数的调用”不能是虚拟的。
虚函数的作用在于通过父类的指针或者引用来调用它的时候能够变成调用子类的那个成员函数。而构造函数是在创建对象时自动调用的,不可能通过父类的指针或者引用去调用,因此也就规定构造函数不能是虚函数。

13、析构函数为虚函数
设置为虚函数可以通过调用基类指针指向子类对象,释放子类空间,可以避免内存泄漏的问题

14、面向对象设计七大原则

  1. 单一职责原则(Single Responsibility Principle)
    每一个类应该专注于做一件事情。

  2. 里氏替换原则(Liskov Substitution Principle)
    超类存在的地方,子类是可以替换的。

  3. 依赖倒置原则(Dependence Inversion Principle)
    实现尽量依赖抽象,不依赖具体实现。

  4. 接口隔离原则(Interface Segregation Principle)
    应当为客户端提供尽可能小的单独的接口,而不是提供大的总的接口。

  5. 迪米特法则(Law Of Demeter)
    又叫最少知识原则,一个软件实体应当尽可能少的与其他实体发生相互作用。

  6. 开闭原则(Open Close Principle)
    面向扩展开放,面向修改关闭。

  7. 组合/聚合复用原则(Composite/Aggregate Reuse Principle CARP)
    尽量使用合成/聚合达到复用,尽量少用继承。原则: 一个类中有另一个类的对象。
    链接:link

15、C++11新特性
auto:让编译器自己分析表达式所属的类型

智能指针:一定程度解决内存泄漏的问题

lambda表达式:简化结构简单的函数代码

容器的初始化列表:原来想要像数组一样初始化的话,需要一个一个来,很麻烦。

类内初始值:总是需要放到构造函数里面初始化,初始化列表倒是不错,但是初始化数据太多就不行了。
右值引用:减少拷贝开销

nullptr:C++11前的NULL一般是是这样定义的 #define NULL 0,这可能会导致一些函数参数匹配问题。而nullptr可以避免这个问题。

16、堆和栈的区别
堆与栈实际上是操作系统对进程占用的内存空间的两种管理方式,主要有如下几种区别:
(1)管理方式不同。栈由操作系统自动分配释放,无需我们手动控制;堆的申请和释放工作由程序员控制,容易产生内存泄漏;

(2)空间大小不同。每个进程拥有的栈的大小要远远小于堆的大小。理论上,程序员可申请的堆大小为虚拟内存的大小,进程栈的大小 64bits 的 Windows 默认 1MB,64bits 的 Linux 默认 10MB;

(3)生长方向不同。堆的生长方向向上,内存地址由低到高;栈的生长方向向下,内存地址由高到低。

(4)分配方式不同。堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是由操作系统完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由操作系统进行释放,无需我们手工实现。

(5)分配效率不同。栈由操作系统自动分配,会在硬件层级对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是由C/C++提供的库函数或运算符来完成申请与管理,实现机制较为复杂,频繁的内存申请容易产生内存碎片。显然,堆的效率比栈要低得多。

(6)存放内容不同。栈存放的内容,函数返回地址、相关参数、局部变量和寄存器内容等。当主函数调用另外一个函数的时候,要对当前函数执行断点进行保存,需要使用栈来实现,首先入栈的是主函数下一条语句的地址,即扩展指针寄存器的内容(EIP),然后是当前栈帧的底部地址,即扩展基址指针寄存器内容(EBP),再然后是被调函数的实参等,一般情况下是按照从右向左的顺序入栈,之后是被调函数的局部变量,注意静态变量是存放在数据段或者BSS段,是不入栈的。出栈的顺序正好相反,最终栈顶指向主函数下一条语句的地址,主程序又从该地址开始执行。堆,一般情况堆顶使用一个字节的空间来存放堆的大小,而堆中具体存放内容是由程序员来填充的。

17、虚函数与多态性
虚函数是用来定义类型特定行为的成员函数,通过指针或引用对成员函数的调用在运行时才进行解析,依据是指针或引用所绑定的对象类型。

多态是指两个具有不同继承关系的两个类对象,调用同一函数产生不同行为。
在OOP范畴下的多态性指的是程序可以通过指针或引用的动态类型获取类型特定行为的能力。

18、常见关键字
const,static,virtual,inline,friend,extern,class,struct,union,template,四个_cast

19、空类中有什么
①构造函数
②析构函数
③拷贝构造函数
④赋值运算符重载函数
⑤取地址运算符重载函数

20、右值引用
左值引用不能绑定到要求转换的表达式,字面值常量或者返回右值的表达式。
而右值引用则只能绑定到即将被销毁的对象上,从而方便自由的将一个右值引用的资源移动到指定对象中。
move库函数可以将一个绑定在左值上的右值引用返回给指定对象。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值