高级语言保研面试准备
-
C++的特点是什么?
- 封装:将数据或函数集合在一个类中
- 继承:派生类可以继承父类的一些数据和函数
- 多态:同一个行为具有多个不同表现形式或形态的能力。运行时,可以通过指向基类的指针,调用派生类中的方法
支持面向对象和面向过程的开发。
-
C++的异常处理机制?
抛出异常和捕捉异常进行处理。
-
c和c++,java的区别?
c是纯过程,c++是对象加过程,java是纯面向对象的
-
纯虚函数?
被virtual修饰的成员函数,基类不实现,放到派生类中实现。
-
什么是内存泄漏?
内存泄漏(Memory Leak)是指程序中已动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。没有delete。
-
java怎么处理对象分配和释放的?
java把内存分为堆栈空间存储,在堆中new的空间不用自己收回,自动垃圾收回。
-
java的特点?
一次编译到处运行,没有指针,完全对象化。
-
c++和c中字符串区别?
c++是类,c中是基本类型函数。
-
c++模板
模板就是实现代码重用机制的一种工具,它可以实现类型参数化,即把类型定义为参数, 从而实现了真正的代码可重用性。模版可以分为两类,一个是函数模版,另外一个是类模版。
-
智能指针
智能指针的作用是管理一个指针,因为普通指针申请的空间在函数结束时常常忘记释放,从而造成内存泄漏。使用智能指针可以很大程度上的避免这个问题,因为智能指针就是一个类,当超出了类的作用域时,类会自动调用析构函数,析构函数会自动释放资源。智能指针的作用原理就是在函数结束时自动释放内存空间,不需要手动释放内存空间。
-
野指针
野指针就是指向一个已删除的对象或者所指向的空间是访问受限的空间的指针。
产生原因:(1)指针变量未初始化
(2)指针释放后之后未置空
(3)指针操作超越变量作用域
-
new与malloc的区别
(1)new分配内存按照数据类型进行分配,malloc分配内存按照指定的大小分配;
(2)new返回的是指定对象的指针,而malloc返回的是void*,因此malloc的返回值一般都需要进行类型转化。
(3)new分配的内存要用delete销毁,malloc要用free来销毁;delete销毁的时候会调用对象的析构函数,而free则不会。
(4)new是一个运算符,malloc是一个库函数。
(5)new如果分配失败了会抛出异常,而malloc失败了会返回NULL。
-
虚函数与纯虚函数
虚函数:不代表该函数没有被实现,而是为了允许用基类的指针来调用派生类的这个函数。
纯虚函数:代表函数没有被实现。定义纯虚函数是为了实现一个接口,起到一个规范的作用,继承这个类必须实现这个函数。
-
虚函数表
虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的,简称为 V-Table。在这个表中,主要是一个类的虚函数的地址表,这张表解决了继承、覆盖的问题,保证其真实反应实际的函数。这样,在有虚函数的类的实例中这个表被分配在了这个实例的内存中,所以,当我们用父类的指针来操作一个派生类的时候,这张虚函数表就显得由为重要了,它就像一个地图一样,指明了实际所应该调用的函数。
C++ 的编译器应该是保证虚函数表的指针存在于对象实例中最前面的位置(这是为了保证取到虚函数表有最高的性能 —— 如果有多层继承或是多重继承的情况下)。 这意味着我们通过对象实例的地址得到这张虚函数表,然后就可以遍历其中函数指针,并调用相应的函数。
-
为什么析构函数必须是虚函数?为什么C++默认的析构函数不是虚函数?
析构函数设置为虚函数可以保证我们new一个派生类时,可以使用基类指针指向该派生类对象,释放基类指针时可以释放掉派生类的空间,防止内存泄漏。
C++默认的析构函数不是虚函数是因为虚函数需要额外的虚函数表和虚表指针,占用额外的内存。而对于不会被继承的类来说,其析构函数如果是虚函数,就会浪费内存。因此C++默认的析构函数不是虚函数,而是只有当需要当作父类时,设置为虚函数。
-
fork函数
用途:创建一个和当前进程映像一样的进程
fork可能有三种不同的返回值:
(1)fork向父进程返回最新创建的派生进程的进程ID;
(2)fork向新创建的派生进程返回0,以告知它已经被成功创建;
(3)如果出现错误,fork返回一个负值;
创建新进程成功后,系统中出现两个基本完全相同的进程,这两个进程执行没有固定的先后顺序,哪个进程先执行要看系统的进程调度策略。
-
类构造和析构顺序
构造: 析构:
基类成员对象的构造函数 派生类的析构函数
基类的构造函数 两者相反 派生类成员对象的析构函数
派生类成员对象的构造函数 基类的析构函数
派生类的构造函数 基类成员对象的析构函数
-
静态多态与动态多态
静态多态有两种实现方式:函数重载与函数模板的使用。
静态多态:也称为编译期间的多态,编译器根据函数实参的类型,可推断出要调用哪个函数,如果没有对应函数则出现编译错误。
动态多态主要是调用虚函数时,根据虚函数表确定具体调用的模块。
动态多态:即运行时的多态,在程序执行期间判断所引用对象的实际类型,根据其实际类型调用相应的方法。
-
const修饰普通函数与成员函数的目的
const修饰函数在类中将成员函数修饰为const表明在该函数体内,不能修改对象的数据成员而且不能调用非const函数
-
C语言参数压栈顺序
从右到左
-
STL六大组件
容器,算法,迭代器,仿函数,配接器(适配器),分配器
-
C++源文件从文本到可执行文件经历的过程
预处理阶段:对源代码文件中头文件、宏定义进行分析和替换,生成.i文件。
编译阶段:将预编译文件转换成特定汇编代码,生成.s文件。
汇编阶段:将汇编文件转化成机器码,生成.o或者.obj文件。
链接阶段:连接所需要的库,形成最终的可执行目标文件,即.out或者.exe文件。
-
引用与指针的区别?
- 引用必须被初始化,指针不必
- 引用初始化以后不能被改变,指针可以改变所指的对象
- 不存在指向空值的引用,但是存在指向空值的指针
- 指针是一个实体,而引用仅是个别名
-
struct和class的区别
共同点:struct和class都可以定义成员和函数,都具有继承、多态。
不同点:
-
class默认权限是private,struct默认权限是public。
-
class可以声明类模板,而struct不可以。
-
-
堆与栈
stack栈区主要是存储函数的局部变量,然后程序结束后操作系统自行回收但是栈区容量比较小。一级缓存。从高地址向低地址移动。
heap堆区是程序里动态分配的内容,堆区的内存容量大,使用灵活,使用后要自行回收。容易产生内存碎片。二级缓存,速度比一级缓存慢。从低地址向高地址移动。
-
const 与 #define 的比较,const 有什么优点?
- const 常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查。而对后者只进行字符替换,没有类型安全检查,并且在字符替换可能会产生意料不到的错误(边际效应) 。
- 有些集成化的调试工具可以对 const 常量进行调试,但是不能对宏常量进行调试。