整理一些面试过程中可能会被问到的面试题:
1.简单介绍一下项目,项目是否有并发编程设计。
2.静态库和动态库的区别?
答:静态库(.a、.lib)和动态库(.so、.dll)。静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库,因此体积较大。 动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在,因此代码体积较小。 动态库的好处是,不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例。
3.多态的实现,虚函数表是一个类有一个,还是一个对象有一个?(是某个类共享一个表,还是每个对象都有一个表)?
答:C++的多态性是在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数。如果对象类型是派生类,就调用派生类的函数;如果对象类型是基类,就调用基类的函数。
多态实现的三个条件是,1.有继承关系2.虚函数重写3.父类指针指向子类对象。
当类中声明虚函数时,编译器会在类中生成一个虚函数表,存在虚函数时每个对象都有一个指向虚函数表的指针。
(重载是相对于一个类之间的,也就是我们之前说的,方法名称相同,但是参数不同;
重写则是在继承关系中出现,也就是在子类和父类之间,一般是子类重写父类的方法)
4.C++空类默认有哪些函数?
答:默认产生:构造函数、拷贝构造函数、析构函数、赋值运算符,以及取址运算符、常量取址运算符。
5.构造函数能是虚函数吗?
答:不能。从存储角度说,虚函数对应一个指向vtable虚函数表的指针,如果构造函数是虚的,就需要通过 vtable来调用,可是对象还没有实例化,也就是内存空间还没有,怎么找vtable呢?所以构造函数不能是虚函数。从使用角度说,虚函数的作用在于通过父类的指针或者引用来调用它的时候能够变成调用子类的那个成员函数。而构造函数是在创建对象时自动调用的,不可能通过父类的指针或者引用去调用,因此也就规定构造函数不能是虚函数。
构造函数可以调用虚函数吗?
答:语法上没问题,但是达不到理想的效果。派生类对象构造期间进入基类的构造函数时,对象类型变成了基类类型,而不是派生类类型。同样,进入基类析构函数时,对象也是基类类型。所以,虚函数始终仅仅调用基类的虚函数(如果是基类调用虚函数),不能达到多态的效果,所以放在构造函数中是没有意义的,而且往往不能达到本来想要的效果。
6.析构函数能是虚函数吗?
答:可以。 析构函数的作用在对象撤销前把类的对象从内存中撤掉,通常系统只会执行基类的析构函数,不执行派生类的析构函数。 将基类的析构函数声明为虚函数,当撤销基类对象的同时也撤销派生类的对象,这个过程是动态关联完成的。 析构函数设为虚函数的原因是为了防止内存泄露。所以建议的方式是将析构函数声明为虚函数。
7.引用和指针的区别,引用和指针使用的时候需要注意什么,有什么区别?初始化引用能否修改指向的对象?
答:本质:引用是别名,指针是地址,具体的:1、引用必须初始化,指针可以任何时候初始化 2、引用后不能再引用其他对像,指针则可以 3、引用不能为空,指针可以为空。
(引用就是个别名,不一定占用运行时的内存。是否占用编译器可以根据实际情况来处理)
8.智能指针?
9.STL库?
10.new和malloc区别
10.1 属性。 new和delete是C++关键字,需要编译器支持;malloc和free是库函数,需要头文件支持。
10.2 参数。 使用new操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算。而malloc则需要显式地指出所需内存的尺寸。
10.3 返回类型。new操作符内存分配成功时,返回的是对象类型的指针,类型严格与对象匹配,无须进行类型转换,故new是符合类型安全性的操作符。而malloc内存分配成功则是返回void * ,需要通过强制类型转换将void*指针转换成我们需要的类型。
10.4 自定义类型。new会先调用operator new函数,申请足够的内存(通常底层使用malloc实现)。然后调用类型的构造函数,初始化成员变量,最后返回自定义类型指针。delete先调用析构函数,然后调用operator delete函数释放内存(通常底层使用free实现)。 malloc/free是库函数,只能动态的申请和释放内存,无法强制要求其做自定义类型对象构造和析构工作。
10.5 重载。C++允许重载new/delete操作符,malloc不允许重载。
10.6 内存区域 new做两件事:分配内存和调用类的构造函数,delete是:调用类的析构函数和释放内存。而malloc和free只是分配和释放内存。 new操作符从自由存储区(free store)上为对象动态分配内存空间,而malloc函数从堆上动态分配内存。自由存储区是C++基于new操作符的一个抽象概念,凡是通过new操作符进行内存申请,该内存即为自由存储区。而堆是操作系统中的术语,是操作系统所维护的一块特殊内存,用于程序的内存动态分配,C语言使用malloc从堆上分配内存,使用free释放已分配的对应内存。自由存储区不等于堆,如上所述,布局new就可以不位于堆中。
10.7 分配失败 new内存分配失败时,会抛出bac_alloc异常。malloc分配内存失败时返回NULL。
10.8 内存泄漏 内存泄漏对于new和malloc都能检测出来,而new可以指明是哪个文件的哪一行,malloc确不可以。
11.并发编程,多线程……
12.TCP/IP
13.大端存储和小端存储
1).大端存储:是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放。 2).小端存储:是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致。
14.栈和队列,用两个栈实现一个队列
15.C++11的特性
16.文件断点续传
思路一:前一次读写行为如果出现中断,记录下此次读写完成的文件内容的位置信息;当“续传开始”则直接将指针移到此处,开始继续读写操作。
思路二:拿到文件,保存文件唯一性标识,切割文件,分段上传,每次上传一段,根据唯一性标识判断文件上传进度,直到文件的全部片段上传完毕。
17.引用头文件时<>和“”的区别?
答:如果<>则只在这些目录下找头文件,如果用""先在当前目录下找,如果找不到则在这些目录下找。
18.重载、重写和重定义
重载发生在同一个类中,函数名称相同,参数不同
重写是发生在派生类和基类之间,若派生类和基类有函数原型相同的成员函数,并用virtual关键字声明(基类成员函数用virtual关键字声明即可,而不管派生类成员函数是否用virtual关键字声明),则此成员函数为重写;若派生类和基类有函数原型相同的成员函数,但没有用virtual关键字声明,则为重定义;
重载是静态绑定,对象类型在编译期间就确定了,重写是动态绑定,对象类型在运行时才确定。
19.多态作用:
答:隐藏实现细节,使得代码能够模块化;扩展代码模块,实现代码重用;
接口重用:为了类在继承和派生的时候,保证使用家族中任一类的实例的某一属性时的正确调用。
20.sizeof()的一个空类值是多少,请解释一下编译器为什么没有让它为零。
答案:每个实例在内存中都有一个独一无二的地址,空类的大小为1,当类不包含虚函数和非静态数据成员时,其对象大小也为1。如果在类中声明了虚函数(不管是1个还是多个),那么在实例化对象时,编译器会自动在对象里安插一个指针指向虚函数表VTable,在32位机器上,一个对象会增加4个字节来存储此指针,它是实现面向对象中多态的关键。而虚函数本身和其他成员函数一样,是不占用对象的空间的。
举个反例,如果是零的话,声明一个class A[10]对象数组,而每一个对象占用的空间是零,这时就没办法区分A[0],A[1]…了。
21.C++中的四种类型转换方式。
重点是static_cast, const_cast,dynamic_cast和reinterpret_cast的区别和应用。其中dynamic_cast作用是将基类的指针或引用安全地转换成派生类的指针或引用,并用派生类的指针或引用调用非虚函数。前提条件:当我们将dynamic_cast用于某种类型的指针或引用时,只有该类型含有虚函数时,才能进行这种转换。
https://www.cnblogs.com/BeyondAnyTime/archive/2012/08/23/2652696.html
22.Const和#define相比有什么优点
1) const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误。 2) 有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试。