根据我个人的面试经历来说,不管是大公司还是小公司,单纯问C/C++语言方面的问题很少,大部分是结合你做的项目问问Linux、计算机网络、操作系统、数据结构、设计模式相关的问题。当然,还有手写代码。关于我面试的各个公司的面试经历请见“2016面经”这篇博文。好啦,咱们就直接进入主题吧,以下是我在公司(爱数、迅雷、CVTE、恒生电子、艺龙旅游……)面试过程中被问到的C/C++方面的问题,我做了一个简单的总结,希望对大家有帮助。
struct和class区别
①默认的访问权限。struct是public的,class是private的。
②class继承默认是private继承,而struct继承默认是public继承。
③“class”这个关键字还用于定义模板参数,就像“typename”。但关键字“struct”不用于定义模板参数。
④如果没有定义构造函数,且所有成员变量全是public的话,可以用大括号初始化struct和class。
⑤如果定义构造函数参数包含所有数据成员,可以用大括号初始化struct和class。
空类默认成员函数
Class Empty
{
Public:
Empty();//构造函数
Empty(const Empty&);//拷贝构造函数
~ Empty();//析构函数
Empty& operator=(constEmpty&);//赋值运算符
Empty* operator&();//对象取地址运算符
const Empty* operator&() const ;//常对象取地址运算符
Empty(Empty &&);//右值构造函数
Empty& operator=(Empty&&);//右值赋值运算符
}
构造函数和析构函数异常
该语句的格式为: throw 表达式;
如果在try语句块的程序段中(包括在其中调用的函数)发现了异常,且抛弃了该异常,则这个异常就可以被try语句块后的某个catch语句所捕获并处理,捕获和处理的条件是被抛弃的异常的类型与catch语句的异常类型相匹配。由于C++使用数据类型来区分不同的异常,因此在判断异常时,throw语句中的表达式的值就没有实际意义,而表达式的类型就特别重要。
构造函数可以抛出异常,C++标准指明析构函数不能、也不应该抛出异常。主要原因有两点:
1)如果析构函数抛出异常,则异常点之后的程序不会执行,如果析构函数在异常点之后执行了某些必要的动作比如释放某些资源,则这些动作不会执行,会造成诸如资源泄漏的问题。
2)通常异常发生时,c++的机制会调用已经构造对象的析构函数来释放资源,此时若析构函数本身也抛出异常,则前一个异常尚未处理,又有新的异常,会造成程序崩溃的问题
继承与组合
继承,破坏了封装性,由于“白盒”复用,父类的内部细节对于子类而言通常是可见的。子类和父类之间紧密耦合,子类依赖于父类的实现,子类缺乏独立性。当父类的实现更改时,子类也不得不随之更改。
组合,“黑盒”复用,整体与局部之间松耦合,彼此相对独立。
继承体现的是一种专门化的概念而组合则是一周后组合的概念。除非用到向上转型,不然优先考虑组合。
malloc/free和new/delete
malloc 和 new 至少有两个不同 : new 返回指定类型的指针,并且可以自动计算所需要大小。malloc 只管分配内存,并不能对所得的内存进行初始化,所以得到的一片新内存中,其值将是随机的。
malloc 与 free 是 C++/C 语言的标准库函数, new/delete 是 C++ 的运算符。它们都可用于申请动态内存和释放内存。对于非内部数据类型的对象而言,光用maloc/free 无法满足动态对象的要求。对象 在创建的同时要自动执行构造函数, 对象在消亡之前要自动执行析构函数。由于 malloc/free 是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数 和析构函数的任务强加于malloc/free 。 因此C++ 语言需要一个能完成动态内存分配和初始化工作的运算符 new ,以及一个 能完成清理与释放内存工作的运算符delete 。注意 new/delete 不是库函数。如果没有足够内存空间而导致malloc申请失败,返回NULL。而new则抛出std::bad_alloc标准异常,不返回NULL。
有了malloc/free为什么还要new/delete?
1) malloc与free是C++/C语言的标准库函数,new/delete是C++的运算符。它们都可用于申请动态内存和释放内存。
2) 对于非内部数据类型的对象而言,光用maloc/free无法满足动态对象的要求。对象在创建的同时要自动执行构造函数,对象在消亡之前要自动执行析构函数。由于malloc/free是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加于malloc/free。
因此C++语言需要一个能完成动态内存分配和初始化工作的运算符new,以及一个能完成清理与释放内存工作的运算符delete。注意new/delete不是库函数。
我们不要企图用malloc/free来完成动态对象的内存管理,应该用new/delete。由于内部数据类型的“对象”没有构造与析构的过程,对它们而言malloc/free和new/delete是等价的。
既然new/delete的功能完全覆盖了malloc/free,为什么C++不把malloc/free淘汰出局呢?
这是因为C++程序经常要调用C函数,而C程序只能用malloc/free管理动态内存。
I/O模型
同步IO和异步IO的区别就在于:数据拷贝的时候进程是否阻塞!
阻塞IO和非阻塞IO的区别就在于:应用程序的调用是否立即返回!
阻塞和非阻塞是指当进程访问的数据如果尚未就绪,进程是否需要等待,简单说这相当于函数内部的实现区别,也就是未就绪时是直接返回还是等待就绪;
而同步和异步是指访问数据的机制,同步一般指主动请求并等待I/O操作完毕的方式,当数据就绪后在读写的时候必须阻塞(区别就绪与读写二个阶段,同步的读写必须阻塞),异步则指主动请求数据后便可以继续处理其它任务,随后等待I/O,