本文源自于个人github仓库:https://github.com/forthespada/InterviewGuide
github仓库内有PDF版本下载方式,欢迎各位star、fork~
立志收录计算机校招、社招面试最全面试八股文,无内鬼来点八股文~
101、引用是否能实现动态绑定,为什么可以实现?
可以。
引用在创建的时候必须初始化,在访问虚函数时,编译器会根据其所绑定的对象类型决定要调用哪个函数。注意只能调用虚函数。
举个例子:
#include <iostream> using namespace std; class Base { public: virtual void fun() { cout << "base :: fun()" << endl; } }; class Son : public Base { public: virtual void fun() { cout << "son :: fun()" << endl; } void func() { cout << "son :: not virtual function" <<endl; } }; int main() { Son s; Base& b = s; // 基类类型引用绑定已经存在的Son对象,引用必须初始化 s.fun(); //son::fun() b.fun(); //son :: fun() return 0; }
需要说明的是虚函数才具有动态绑定,上面代码中,Son类中还有一个非虚函数func(),这在b对象中是无法调用的,如果使用基类指针来指向子类也是一样的。
102、全局变量和局部变量有什么区别?
生命周期不同:全局变量随主程序创建和创建,随主程序销毁而销毁;局部变量在局部函数内部,甚至局部循环体等内部存在,退出就不存在;
使用方式不同:通过声明后全局变量在程序的各个部分都可以用到;局部变量分配在堆栈区,只能在局部使用。
操作系统和编译器通过内存分配的位置可以区分两者,全局变量分配在全局数据段并且在程序开始运行的时候被加载。局部变量则分配在堆栈里面 。
《C++经典面试题》:https://www.cnblogs.com/yjd_hycf_space/p/7495640.html
103、指针加减计算要注意什么?
指针加减本质是对其所指地址的移动,移动的步长跟指针的类型是有关系的,因此在涉及到指针加减运算需要十分小心,加多或者减多都会导致指针指向一块未知的内存地址,如果再进行操作就会很危险。
举个例子:
#include <iostream> using namespace std; int main() { int *a, *b, c; a = (int*)0x500; b = (int*)0x520; c = b - a; printf("%d\n", c); // 8 a += 0x020; c = b - a; printf("%d\n", c); // -24 return 0; }
首先变量a和b都是以16进制的形式初始化,将它们转成10进制分别是1280(5*16^2=1280)和1312(5*16^2+2*16=1312), 那么它们的差值为32,也就是说a和b所指向的地址之间间隔32个位,但是考虑到是int类型占4位,所以c的值为32/4=8
a自增16进制0x20之后,其实际地址变为1280 + 2*16*4 = 1408,(因为一个int占4位,所以要乘4),这样它们的差值就变成了1312 - 1280 = -96,所以c的值就变成了-96/4 = -24
遇到指针的计算,需要明确的是指针每移动一位,它实际跨越的内存间隔是指针类型的长度,建议都转成10进制计算,计算结果除以类型长度取得结果
104、 怎样判断两个浮点数是否相等?
对两个浮点数判断大小和是否相等不能直接用==来判断,会出错!明明相等的两个数比较反而是不相等!对于两个浮点数比较只能通过相减并与预先设定的精度比较,记得要取绝对值!浮点数与0的比较也应该注意。与浮点数的表示方式有关。
105、方法调用的原理(栈,汇编)
1) 机器用栈来传递过程参数、存储返回信息、保存寄存器用于以后恢复,以及本地存储。而为单个过程分配的那部分栈称为帧栈;帧栈可以认为是程序栈的一段,它有两个端点,一个标识起始地址,一个标识着结束地址,两个指针结束地址指针esp,开始地址指针ebp;
2) 由一系列栈帧构成,这些栈帧对应一个过程,而且每一个栈指针+4的位置存储函数返回地址;每一个栈帧都建立在调用者的下方,当被调用者执行完毕时,这一段栈帧会被释放。由于栈帧是向地址递减的方向延伸,因此如果我们将栈指针减去一定的值,就相当于给栈帧分配了一定空间的内存。如果将栈指针加上一定的值,也就是向上移动,那么就相当于压缩了栈帧的长度,也就是说内存被释放了。
3) 过程实现
① 备份原来的帧指针,调整当前的栈帧指针到栈指针位置;
② 建立起来的栈帧就是为被调用者准备的,当被调用者使用栈帧时,需要给临时变量分配预留内存;
③ 使用建立好的栈帧,比如读取和写入,一般使用mov,push以及pop指令等等。
④