C++ 秋招面试记录

1.必须使用拷贝构造函数的情况:

a.用类对象初始化另一个类对象
b.函数返回值是类对象的时候
c.函数形参是类对象的时候

2.Vector的底层实现

Vector内部维护一个指针指向一段连续的内存,当内存不够时候,根据其扩充机制进行内存扩充,一般扩充到1.5倍或者2倍,具体取决于编译器。扩充机制:当前连续存储空间不够实用时候,另寻找一段大小为当前大小1.5倍或2倍的内存空间,将原内存位置的数据复制过来,再释放掉原控制内存。

3.map几种插入方式

a.用insert函数插入pair数据
b.用insert函数插入value_type数据
c.在insert函数中使用make_pair()函数
d.数组插入方式

4.STL中list的实现

使用双向链表实现,方便插入删除

5.deque是怎么实现的

是双向开口的连续线性空间,在头部和尾部插入删除数据,没有容量限制,因为它是以动态地分段连续空间组合而成,随时可以再增加一段新的空间并链接起来。要对deque排序,搞笑的做法是将deque复制到一个vector里运用sort排序后再复制回deque。

6.STL中vector删除元素,迭代器如何变化?

使用earse删除元素后,后面的迭代器会失效,返回下一个有效迭代器
删除多余的内存空间可以使用swap,swap建立一个临时对象并运用复制构造函数复制原对象中的元素,再交换原对象与临时对象的内存空间,原对象的内存空间交给临时对象后会在临时对象被销毁时候被析构函数释放掉,这样就释放掉了多余的内存空间,在C++11中提供了shrink_to_fit()函数。

7.C++构造函数有几种?

a.默认构造函数:
b.拷贝构造函数:用一个类对象初始化另一个类对象时
c.普通构造函数:程序员定义的构造函数
d.移动构造函数:使用临时对象初始化一个新对象时候,将临时对象指针所指向的内存单元移交给新对象的指针,避免了拷贝带来的开销,新对象会被析构销毁
e.转换构造函数:当构造函数接收到一个不同于其类类型的形参时,会将其转换成一个类对象,例如string类提供了将C字符串转换成string的转换构造函数

8.this指针

this指针是类对象指针
this指针只在成员函数中使用,在静态函数、全局函数内不能使用
this指针只在成员函数内有定义,存储位置因编译器而不同
delete this 会调用析构函数释放内存,this会指代不明确,在析构函数上使用delete this ,delete this 会调用析构函数,析构函数在调用delete this, 于是陷入死循环。

9.Vector如何实现的?

vector内部维护的是一段线性连续内存空间,有三个迭代器:start,finish,end_of_storage。分别指向目前使用的头位置、目前使用的尾位置、目前可用的尾位置。当finish指向end_of_storage时满载,此时需要重新寻找一段线性连续空间并且其大小为原来的1.5倍或者两倍,并将原来的内存空间上的元素的复制过来,在释放掉原来的内存空间。

10.深复制和浅复制的区别?

深复制会复制对象所指的存储空间,浅复制并不会将内存空间进行复制。

11.C与C++的区别

C++是面向对象的编程:将数据和使用数据的函数封装成类,由类对象之间的交互完成程序实现,C是面向过程的编程:按照问题解决顺序一步一步实现代码;
C++提供了运算符重载功能,C没有
C++提供了函数重载功能,C没有
C++利用new delete代替了C中的malloc free
C++提供STL库使用更加方面,C++设置了命名空间减少了命名冲突,提供了智能指针

12.指针调用函数过程

先将指针压入栈,再将函数参数从右向左的顺序压入栈内,再将函数的地址压入站内。

13.C++的特性是什么?

封装:将数据和函数封装成类,在类的内部为这些成员设置不同的权限,对外提供接口,使得无需了解类的内部实现就可以通过类的接口使用类。
继承:一个类使用另一个类的部分数据和部分方法,可以实现代码复用,被继承的类叫基类/父类,继承基类的类叫派生类/子类,有三种继承方式:公有继承,保护继承,私有继承
多态:让基类可以使用派生类的功能,在基类中声明虚函数,编译时期生成虚函数表,虚表中存储了函数地址,当使用函数时通过this指针去调用虚函数表在虚表中查找对应的函数地址,再去调用。

14.为什么静态函数不可以声明为虚函数?

静态成员函数不属于任何一个类对象,是类中共有的,无法使用this指针,而虚函数的使用要依靠this指针调用虚函数表指针在虚函数表中去查找虚函数的地址。

15.构造函数为什么不可以是虚函数?

虚函数表指针是在构造函数中初始化的,如果构造函数也为虚函数,那就意味着通过虚函数表指针去调用构造函数,而在构造函数调用之前虚表指针还未被初始化,另外,虚函数的调用需要通过对象指针来使用,而调用构造函数时对象还没有被创建完成,对象指针也不存在。

16.模板函数为什么不能被定义成虚函数?

定义了模板函数,并且在代码中使用了该模板,则在编译时期就会对该模板进行实例化,而虚函数是在运行过程中进行绑定。

17.内联函数为什么不能定义成虚函数?

内联函数无法进行取地址操作,在动态调用时无法获取其位置
内联函数在编译时复制,而虚函数在程序运行中绑定

18.虚函数与纯虚函数的区别

纯虚函数可以被定义,必须在类外,必须在派生类中对虚函数进行重写,含有纯虚函数的类是抽象类,派生类只继承接口
虚函数只能在基类中声明,在派生类中可以选择实现或不实现,不实现时在派生类中继承基类的声明和缺省实现。

19.智能指针

C++11引入了智能指针,一个独占式智能指针std::unique_ptr和一个共享式智能指针std::shared_ptr,unique_ptr拥有对其所指向对象的唯一控制权,在被销毁时,所指向的对象也被销毁;而shared_ptr对其所指向的对象的控制权是共享的,也就多个shared_ptr可以指向同一对象,只有在最后一个shared_ptr被销毁时其所指向的对象才会被销毁。

20.值参数传递和引用参数传递的区别

值参数传递时在函数内部会建立一个实参的副本,在栈上开辟新空间将实参的副本压入栈内,后续操作是针对这个副本进行的;
引用参数传递在传值时传递的是实参对应的地址,不会创建实参副本,也不需要在栈上开辟新的空间,后续操作是针对实参本身进行的。

21.全局变量和静态变量的区别

全局变量具有外链接性,在同一工程下的另一个文件中使用extern声明引用此全局变量,那就可以在该文件中使用这个变量,而静态变量是具有隐秘性的,即使在另一个文件下使用extern声明引用这个变量,那也不能使用此变量。

22.struct与class的区别

struct默认成员是公有的,class默认成员是私有的
struct默认公有继承,class默认私有继承
struct关键字不能用于定义模板参数,class关键字可以用于定义模板参数。

23.空类占用一个字节

24.指针和引用的区别

指针可以多级使用,定义时可以不初始化,初始化后可以更改指向的对象;
引用只能一级使用,必须初始化,初始化后不可修改。

25.程序运行的过程

1.预处理:对宏定义以及头文件等进行相关操作;
2.编译:查看语法错误;
3.汇编:将代码文件会变成机器可识别的二进制代码;
4.链接:将多个文件链接成一个可执行文件;
5.执行可执行文件。

26.strlen()和sizeof()的区别

strlen()是函数,sizeof()是关键字;
strlen()参数必须是字符型指针,sizeof()参数可以是数组、指针、类型、对象、函数等;
strlen()在运行过程中计算值,sizeof()在编译时计算返回值,因此不能计算动态分配内存的大小;
strlen()返回字符串实际长度,sizeof()返回对象所占用的最大字节数。

27.左值与右值的区别

左值:有名称、可获取存储地址的表达式为左值;反之为右值。

28.内存分为几个区

1.栈:函数中的局部变量存储在栈上,分配和释放由处理器内置指令集操作,效率高,但存储空间有限;
2.堆:动态分配的内存位于堆上,编译器不负责堆上的内存释放,需要程序员手动释放,若未释放在程序结束后,由操作系统自动回收;
3.自由存储区:
4.全局/静态存储区:存储全局变量和静态变量;
5.常量区:存放常量区、不允许被改变;
6.程序代码区:存放函数体的二进制代码。

29.继承是怎样与动态内存分配进行互动的

当基类和派生类都采用动态分配内存时,派生类的析构函数、复制构造函数和赋值运算符都必须使用相应的基类方法来处理基类元素,析构函数是自动实现的;复制构造函数通过在初始化成员列表中调用基类的复制构造函数来完成,否则自动调用基类默认构造函数;对于赋值运算符,通过使用作用域解析运算符显式地调用基类的赋值运算符完成。

30.map的下标运算符[]和find()有什么区别?

下标运算符[]是利用key去查找,如果找到则返回对应的value,不存在则插入该key;find是利用key在map中查找,如果找到则返回该key对应的迭代器,未找到则返回map末尾迭代器。

31.函数调用过程

1.将函数参数从右往左压入栈中;
2.将函数的返回地址压入栈中,即当前指令的下一条指令地址,函数返回后跳转到该地址;
3.将主调函数的帧基指针压栈,即保存旧栈帧中的帧基指针以便函数返回时恢复旧栈帧;
4.使用主调函数的栈顶指针给新栈帧复制,形成新的栈帧结构,即确定当前函数栈帧的栈底指针和栈顶指针;
5.移动新的栈基指针,将函数局部变量压入栈;
6.函数执行完之后,局部变量出栈,恢复之前的栈帧结构,并取出函数返回地址进行返回。

32.运算符重载

不能重载的运算符:成员运算符.、作用域运算符::、sizeof()、条件运算符?、typeid
只能通过成员函数进行重载的运算符:赋值运算符=、()、下标运算符[]、指针访问运算符->

33.static关键字的作用

1.修饰局部变量:
只能在首次函数调用时初始化,再次调用时不会初始化
生命周期与程序相同,但作用域为局部
2.修饰全局变量:
在该变量所在的文件内都是可见的,在该文件外是不可见的
3.修饰函数时候:
在该函数所在的文件内都是可见的,在该文件以外具有隐藏性
4.修饰成员变量:
该变量只有一份实体,所有的类对象共享这一个实体
不需要实例化对象也可以访问
不能再类内部初始化,需要在类外初始化,初始化时不加static
5.修饰成员函数
静态成员函数不接受this指针,只能访问类的静态成员
不能被声明为虚函数
不需要实例化对象就可以访问

34.const关键字的作用

无类:const常量在定义时必须初始化,之后不能更改;const形参可接受const和非const类型的实参
有类:const修饰成员变量:只能通过构造函数初始化列表进行初始化,并且必修有构造函数;不能同类对象对const变量的值可以不同,所以不能在类中声明时初始化。
const修饰成员函数:const对象不可以调用非const成员函数,非const对象可以调用非const成员函数也可以调用const成员函数。

35.strcpy(dst, src)、strncpy(dst, src, size_t len)与strcpy_s(dst, size_t num, src)的区别

strcpy(dst, src)将src内容复制到dst,若src长度大于dst长度并不会报错,意外取决于编译器;
strncpy(dst, src, size_t len)将src中的[0,len]个字符复制到dst中,src长度小于len时dst中多余的位置置为null;
strcpy_s(dst, size_t num, src)将src内容复制到dst时会检查dst的长度是否大于等于num,否则会报错。

36.进程于线程的区别

1.进程是资源分配的基本单位,线程是CPU调度的基本单位;
2.进程拥有独立的地址空间,线程拥有独立的栈空间,同一进程中的多个线程共享代码段、数据段、堆,同一进程的所有线程共享该进程的所有资源;
3.进程安全性高,因为进程有独立地址空间,一个进程崩溃后,在保护模式下不会对另外进程造成感染;而一个线程死掉就等于一个进程就死掉;
4.进程之间相互独立,通信机制较为复杂,线程共享数据段所以通讯机制简单。

如果对您有用的话,请点个赞吧!

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

没伞的行者

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值