自动驾驶-机器人-slam-定位面经和面试知识系列07之C++STL面试题(03)

这个博客系列会分为C++ STL-面经、常考公式推导和SLAM面经面试题等三个系列进行更新,基本涵盖了自己秋招历程被问过的面试内容(除了实习和学校项目相关的具体细节)。在知乎和牛客也会同步更新,全网同号(lonely-stone或者lonely_stone)。
关于高频面试题和C++ STL面经,每次我会更新10个问题左右,每次更新过多,害怕大家可能看了就只记住其中几个点。(在个人秋招面试过程中,面试到后面,发现除了个人项目和实习经历外,个人所记录的内容基本能涵盖面试官能问到的)
(另外个人才疏学浅,如果所分享知识中出现错误,请大家指出,避免误导其他人)

1. 在c++中,class和struct做类型定义是只有两点区别

  • 默认继承权限不同class默认是private继承,而struct是public继承。
  • Class还可用于定义模板参数,如typename,但是struct不能。
  • c++一直保留struct是保持与C的兼容。

2. C++强制转换

  • static_cast是一个强制类型转换操作符(显示转换),除此之外,还有static_cast, dynamic_cast, const_cast, reinterpert_cast
  • static_cast用于多态类型的转换,不执行运行时类型检查(转换安全性不如dynamic_cast),通常用于转换数值类型(float->int等)。
  • dynamic_cast运行时执行类型检查

3. 静态库与动态库区别

  • LIB包含了函数所在的DLL文件和文件中函数为止的信息(入口),代码由运行时加载在进程空间中的DLL提供,称为动态链接库。
  • 另一种则是LIB包含函数本身,在编译时直接将代码加入程序中。
  • 关于lib和dll区别:
    • Lib是编译时用到的,dll是运行时用到的。如果要完成源代码的编译,只需要lib;如果要使动态链接的程序运行起来,只需要dll。
    • 如果有dll文件,那么lib文件就只是一些索引信息,记录dll中函数的入口和位置,dll是函数的具体内容;如果只有lib文件,那么lib文件是静态编译出来的,索引和实现都在其中,使用的时候就是lib文件,不用再挂动态库,缺点就是应用程序比较大,而且不灵活。
    • 动态链接的情况下,有两个文件:LIB和DLL。LIB 里面是DLL里面导出的函数名称和位置,DLL包含实际的数据和函数。

4. Linux程序运行出现segmentation fault(core dumped)的通用解决办法

问题原因:segmentation fault多为内存不当操作造成。空指针,野指针的读写操作,数组越界访问,破坏常量等。对每个指针声明后进行初始化为NULL是避免这个问题的好办法,而要排除问题就是要调试。

更为具体的原因为:

  • 内存访问越界
    • 数组访问越界
    • 搜索字符串时,依靠字符串结束符来判断字符串是否结束,但是字符串没有正常的使用结束符。
    • 使用strcpy,strcat,sprintf,strcasecmp等字符串操作函数,将目标字符串读/写爆。应该使用strncpy,strlcpy,strncat,strlcat,snprintf,strncmp,strncasecmp等函数防止读写越界。
  • 多线程程序使用了线程不安全的函数
  • 多线程读写的数据未加锁保护
  • 非法指针
    • 使用空指针
    • 随意使用指针转换。一个指向一段内存的指针,除非确定这段内存原先就分配为某种结构或类型,不然不要随意转换指向的数据类型。
  • 堆栈溢出:不要使用大的局部变量(因为局部变量都分配在栈上)
  • 可以使用valgrind来做内存调试工具

5. 拷贝构造函数

通过拷贝对象的方式创建一个新对象,有两种形式,book(book &b)和book(const book &b)。

为什么拷贝构造函数的参数一定要是对象引用呢?

如果不是引用,而是通过传值的方式将实参传给形参,这中间本身就会经历一次拷贝过程,而对象拷贝则必须调用拷贝构造函数,如此一来就形成了一个死循环。
这个问题是我面试的时候被问到没答上来,最后询问面试官回答的

6. 结构体内存对齐问题

  • 结构体内成员按照声明顺序存储,第一个成员地址和整个结构体地址相同。
  • 未特殊说明时,按结构体中size最大的成员对齐(若有double,按8字节对齐)
  • 那为什么要对齐呢,是因为对齐的话就放在同一个地方,不需要多次多地方读写

7. 指针和引用的区别

  • 指针是一个变量,存储的是一个地址,引用跟原来的变量实质是同一个东西,是原变量的别名
  • 指针可以多级,引用只有一级
  • 指针可以为空,引用不能为NULL且在定义时必须初始化
  • 指针可以在初始化后改变指向,而引用在初始化后不可再改变
  • sizeof指针得到的是本指针的大小,sizeof引用得到的是引用所指向变量的大小
  • 当把指针作为函数参数传递时,也是将实参的一个拷贝传递给形参,两者指向的地址相同,但不是同一个变量,在函数中改变这个变量的指向不影响实参,而引用却可以。
  • 引用只是别名,不占用具体存储空间,只是声明没有定义;指针是具体变量,需要占用存储空间
  • 引用在声明时必须初始化为另一变量,一旦出现必须为typename &varname形式;指针的声明和定义可以分开,可以先只声明指针变量而不初始化,等用到时再指向具体变量。
  • 引用一旦初始化之后就不可以再改变(变量可以被引用多次,但引用只能作为一个变量引用);指针变量可以重新指向别的变量。
  • 不存在指向空值的引用,必须有具体实体了但是存在指向空值的指针。

8. 区别以下指针类型


int *p[10]//表示指针数组,强调数组概念,是一个数组变量,数组大小为10, //每个元素都是指向int类型的指针变量 
int (*p)[10]//表示数组指针,强调是指针,只有一个变量,是指针类型,指向int类型的数组,数组大小为10 
int *p(int)//是函数声明,函数名是p,参数是int类型的,返回值是int *类型 
int (*p)(int)//是函数指针,强调是指针,指向具有int型参数的函数,并且返回值是int类型的

9. 哪几种情况必须要用到初始化成员列表?

  • 初始化一个const成员,
  • 初始化一个reference成员
  • 调用一个基类的构造函数,而该函数有一组参数
  • 调用一个数据成员对象的构造函数,而该函数有一组参数

10. 类的对象存储空间?

  • 非静态成员的数据类型大小之和
  • 编译器加入的额外成员变量(如指向虚函数表的指针)
  • 为了边缘对齐优化加入的padding(就是给第1点的成员变量对齐数据类型的时候)

11. 构造函数能否声明为虚函数或者纯虚函数,析构函数呢?

  • 析构函数:
    • 析构函数可以为虚函数,并且一般情况下要定义为虚函数
    • 只有在基类析构函数定义为虚函数时,调用操作符delete销毁指向对象的基类指针时,才能准确调用派生类的析构函数,才能准确销毁数据。
    • 析构函数可以是纯虚函数,含有纯虚函数的类是抽象类,此时不能被实例化。但派生类可以根据自身需求重新改写基类中的纯虚函数。
  • 构造函数:
    • 构造函数不能定义为虚函数。在构造函数中可以调用虚函数,不过此时调用的是正在构造的类中的虚函数,而不是子类的虚函数,因为此时子类尚未构造好。

你可能感兴趣的:(面试,c++,职场和发展)