C++ 面试知识点总结
记录刷题的细节内容,算法与 C++ 特性(等之后有空再优化)。
static 定义静态局部变量特点
- 在全局数据区分配内存
- 首次初始化执行后,之后函数调用不再初始化
- 无显式初始化时,自动初始化为 0
局部变量、全局变量与动态数据的内存区域
局部变量存在于堆栈中,全局变量存在于静态区中,动态申请的数据存在于堆中。
模板
1 | |
C++ 虚函数概念
C++ 中的虚函数的作用主要是实现了多态的机制。基类定义虚函数,子类可以重写该函数。
当子类重新定义了父类的虚函数后,当父类的指针指向子类对象的地址时,即 B b; A *a = &b;,父类指针根据赋给它的不同子类指针,动态的调用子类的该函数,而不是父类的函数。而如果使用了 virtual 关键字,程序将根据引用或指针指向的对象类型来选择方法,否则使用引用类型或指针类型来选择方法。
1 | |
vector 的函数 erase()
一次只删除一个元素,返回一个迭代器指针,指向下一个元素。
默认只读模式打开文件
ios::app 和 ios::app | ios::out 是一个意思,只能输出不能输入。
数组的定义区别理解
1 | |
函数模板
函数模板必须由编译器根据程序员的调用类型实例化为可执行的函数。
类模板的成员函数都是函数模板。
没使用过的成员函数(即函数模板)不会被实例化。
双目运算符的判断机制
&& 和 || 的判断机制:A&&B,若 A 为假,直接返回 false,B 不执行;若 A 为 true,继续执行 B。A||B,若 A 为 true,直接返回 true,B 不执行。
C++ 中的 switch
switch 后面的”表达式”,可以是 int、char 和枚举型中的一种,不能是 float 型变量
case 后面必须是”常量表达式”,表达式中不能包含变量
switch 后的表达式加了分号;非法
unsigned
unsigned 为无符号整数,取值范围为 0-255,永远不可能小于零,最好不要做控制条件。
派生类继承编译
1 | |
引用
引用是一个对象的别名,引用类型引用(refer to)另外一种类型。如 int &refVal = val;
- 引用必须初始化
- 引用与其初始值是**绑定(bind)**在一起的,而不是拷贝
- 值传递以拷贝实参的方式,传递给形参
C++ STL 的 string 库与 C 风格字符串
C++ STL(Standard Template Library)string 库中的风格比 C 风格的字符串更加安全、高效。
while 与 for
- while: 为不确定迭代的次数时使用,例如读取数据
- for: 确定范围时使用,也可以省略初始值、条件以及表达式
异常问题
throw、try、异常块;
throw: 异常表达式表示其遇到无法处理的问题,引发(raise)的异常
try: try 和一个或多个 catch 块配合使用,一般的 try 抛出的某个异常会被某个 catch 捕获处理,故 catch 称为异常处理代码。
class 与 struct 区别
在于访问权限
class 第一个访问说明符之前的成员为 private
struct 第一个访问说明符之前的成员为 public
使用非成员版本的 swap 是一个好习惯
swap(c1, c2) 与 c1.swap(c2) 等价,但最好使用前者。
泛型算法
头文件 #include <algorithm> 和 #include <numeric> 中,标准库提供了超过 100 个算法,所以说阅读源代码非常重要。
1 | |
关联容器(hash、map、set)
map:map<string, int> word_count = {{"a", 1}, {"b", 2}};set:set<string> exclude = {"the", "a"};- unordered_map(hash 组织 map)
- unordered_set(hash 组织 set)
字符指针
char *str[3] = {"stra","strb","strc"}; 是一个指针数组;char *p = str[0];实际上 p 指向第一个字符串,所以字符串加 1,则指向字符串的下一个字母,而并非是下一个字符串。
static 与非 static、全局变量与局部变量
无论是 static 还是非 static 的全局变量,如果不加限制随意访问的话,容易出现同步问题。
无论是 static 还是非 static 的局部变量,每个线程都是私有的,其他线程不会对其进行干扰。
C/C++ 中 main 函数
main 函数是 C/C++ 程序的入口函数,为必须存在的函数。
throw、catch、try
- throw 是抛出异常的关键字,try 是尝试执行可能有异常代码的关键字,catch 是捕获异常的关键字
- 可能抛出异常的代码块都应该放在 try 代码块中
- catch 捕获相应的异常,可以有多级 catch 代码块来捕获不同级别的异常
- 被捕获的异常可以再次抛出
线程
线程使用了
wait方法,会强行打断当前操作,进入阻塞(暂停)状态,然后需要notify方法或notifyAll方法才能进入就绪状态。
枚举变量
枚举变量是全局变量的情况下,枚举值的缺省值是 0,不是枚举的第一个值。其他情况,其值是不定的,而且不限定于所列出的枚举值。
全局变量时初始化为 0,局部变量时初始化为随机值。
unsigned 指针运算
1 | |
数组、指针、字符串的长度计算
对字符串进行 sizeof 操作的时候,会把字符串的结束符 \0 计算进去的。
进行 strlen 操作求字符串的长度的时候,不计算 \0 的。
数组作为函数参数传递的时候,已经退化为指针了,Func 函数的参数 str_arg 只是表示一个指针,那个 str_arg[] 括号中的数值不起任何作用。
强制类型转换后指针的类型
1 | |
p 的类型为 char *,p++ 后 p 指向 str 数组的第 2 个元素即字母 “l” 的位置。
p1 的类型为 int *,p1++ 后 p1 指向的位置增加 4 个字节,指向 str 数组中的第 6 个元素即字母 t 的位置。
因此最后 p 的内容为 to test something。
类
- 在类中,如果为空类,则类占用 1 个字节
- 一旦类中有其他的占用空间成员,则这 1 个字节就不在计算之内
- 一个类只有一
int则占用 4 字节而不是 5 字节 - 如果只有成员函数,则还是只占用 1 个字节,因为类函数不占用空间
- 但是由于虚函数存在一个虚函数表,需要 4 个字节,数据成员对象如果为指针则为 4 字节,注意有字节对齐,如果为 13 字节,则进位到 16 字节空间
buffer
1 | |
动态分配在堆区
动态分配在堆区,其他的均不在堆区。
操作系统中用户态切换到内核态的 3 种方式
a. 系统调用
b. 异常
c. 外围设备的中断
函数嵌套
若有如下函数定义,这种嵌套定义根本算不出结果,所以函数嵌套定义肯定不行。
1 | |
静态变量初始化
在 C++ 中,类的静态成员(static member)必须在类内声明,在类外初始化。
1 | |
为什么?因为静态成员属于整个类,而不属于某个对象,如果在类内初始化,会导致每个对象都包含该静态成员,这是矛盾的。
能在类中初始化的成员只有一种,那就是静态常量成员。
这样不行:
1 | |