C++常见面试题(一)
结构体、类、共用体
结构体:把不同类型的数据组合成一个整体,自定义类型,默认为public;
类:将数据表示和操纵数据的方法组合成一个整洁的包,默认为private;
共用体:让不同类型的变量共用一段内存,只能同时存储其中一种类型。
内存对齐
结构体或类的自身对齐值:其成员中自身对齐值最大的;
指定对齐值:#pragma pack(n),n=1,2,4,8,16改变系统的对齐系数;
数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中小的。
结构体:sizeof(struct)是内存对齐后所有成员长度的加和。
static
对变量:
1.在局部变量之前加上关键字static,即被定义为局部静态变量。
内存中的位置:静态存储区;
初始化:0;
作用于:局部作用域
2.在全局变量之前加上static,即全局静态变量。
内存中的位置:静态存储区;
初始化:0;
作用域:从定义开始到文件结束。
类中的成员变量:
用static修饰类的数据成员使其成为类的全局变量,类的所有对象共享,包括派生类的对象。static成员必须在类外初始化,加上类作用域。
类中的成员函数:
用static修饰成员函数,使其只存在这一个函数,所有对象共享,不含this指针。
静态成员可以独立访问。
静态成员函数的实现中不能直接引用类中的非静态成员。
const
限定变量为不可修改;
限定成员函数不可以修改任何数据成员;
const与指针
int a = 0;
int b = 1;
int *const p1 = &a; /*p1指向了a的地址,为常量指针,p1只能指向a的地址,可以通过*p1修改变量值
*p1 = 1 //正确
p1 = &b //错误*/
const int *p2 = &a;/*p2指向一个int类型的地址,不可以用*p2修改变量值
*p2 = 1 //错误
p2 = &b 正确*/
指针与引用
本质区别:指针是一个新变量。引用是一个别名。
指针可以有多级,引用只有一级;
指针可以为空,引用必须在定义时初始化;
指针的值初始化后可修改,引用初始化后不可修改;
sizeof引用是所指向变量的大小,sizeof指针是指针本身的大小
多态、虚函数、纯虚函数
多态:一个接口,多种方法。
编译时多态:运算符重载;
运行时多态:继承、虚函数。
虚函数:在基类用virtual修饰的成员函数,允许在派生类中对基类的虚函数重新定义。
基类的虚函数可以有函数体,基类也可以实例化;
虚函数有函数体;
虚函数在子类中可以不覆盖;
构造函数不能是虚函数。
纯虚函数:基类中为其派生类保留一个名字,以便派生类根据需要进行定义。
抽象类:包含一个纯虚函数的类;
抽象类不可以实例化,但可以定义指针;
对象不包含虚函数表,只有虚指针,类有虚函数表,派生类会生成一个兼容基类的虚函数表。
子类不能继承父类的函数
构造函数,析构函数,拷贝构造函数,operator=函数,友元函数。
重载(overload)和覆盖(override)
重载:多个同名函数,参数不同;同一层级的函数;静态绑定;编译期绑定。
覆盖:子类重新定义父类函数的方法;动态绑定。
基类的析构函数是虚函数?
动态绑定,不会造成潜在的内存泄漏。
C++语言描述
C语言代表过程化编程C++在C语言基础上添加的类代表面向对象语言、C++模板支持泛型编程。支持多种编程范式:面向对象编程、泛型编程和过程化编程。
面向对象
一种对现实世界理解和抽象的方法、思想,通过将需求要素转化为对象进行问题处理的一种思想。
C++函数传参方式
值传递,指针,引用。
C++变量内存分配
栈:由编译器自动分配释放,存放函数的参数值,局部变量值等。
堆:由程序员分配释放,若不主动释放,程序结束时可能由OS回收。
全局/静态存储区:初始化的全局变量和静态变量在一块区域,未初始化的在相邻的另一块区域。程序结束后由OS释放。
常量存储区:常量字符串。程序结束后由OS释放。
各个排序算法性质
vector中size()和capacity()
sizeof():容器当前拥有的元素个数;
capacity():容器在必须分配存储空间之前可以存储的元素总数。
map和set
底层实现:红黑树。
红黑树性质:
1.节点是红色或黑色;
2.根节点是黑色;
3.每个叶节点是黑色;
4.每个红色节点的两个子节点都为黑色(从每个叶子到根的所有路径上不能有两个连续的红色节点)
5.从任一节点到其每个叶子的所有路径都包含相同数目的黑色节点。
OSI七层模型与TCP/IP模型
TCP
为什么不是2次握手?答:防止已失效的连接请求又传送到服务器端。
TCP连接的每一端都有两个窗口:发送窗口和接收窗口。
TCP的可靠传输机制用字节的序号进行控制。所有的确认都是基于序号而不是基于报文段。
TLV数据传输实例
TCP流量控制
流量控制:让发送方的发送速率不要太快,要让接收方来得及接收。利用滑动窗口机制可以实现。
TCP的拥塞控制方法
四种算法:慢开始、拥塞避免、快重传和快恢复。
当拥塞窗口cwnd增长到慢开始门限值ssthresh时(图中①,此时拥塞窗口cwnd=16),就改为执行拥塞避免算法,拥塞窗口按线性规律增长。
当拥塞窗口cwnd=24时,网络出现了超时(图中②),发送方判断为网络拥塞。于是调整门限值ssthresh=cwnd/2=12,同时设置拥塞窗口cwnd=1,进入慢开始阶段。
当拥塞窗口cwnd=ssthresh=12时(图中③,新的ssthresh值),改为执行拥塞避免算法,拥塞窗口按照线性规律增长。
当拥塞窗口cwnd=16时(图中④),发送方一连收到3个对同一个报文段的重复确认(图中标记为3-ACK)。这时,发送方调整门限值ssthresh=cwnd/2=8,同时设置拥塞窗口cwnd=ssthresh=8(图中⑤),并开始执行拥塞避免算法。
TCP报文格式
序号:用来标识从TCP源端向目的端发送的字节流。
确认号:Ack序号,只有ACK标志位为1时,确认序号字段才有效。
标志位:共6个;
URG:紧急指针有效;
ACK:确认序号有效;
PSH:接收方应尽快将这个报文交给应用层;
RST:重置连接;
SYN:发起一个新连接,同步序号;
FIN:释放一个连接。
TCP三次握手
四次挥手
为什么建立连接是三次,关闭连接是四次?
服务器在LISTEN状态下,收到建立连接请求SYN报文后,把ACK和SYN放在一个报文里发送给客户端。
关闭连接时,当收到对方的FIN报文时,仅表示对方不再发送数据,因此还能接收数据。未必全部数据都已发送给对方,所以不能立即close。所以发送一些数据给对方后,再发送FIN报文给对方表示同意现在关闭连接。因此,ACK和FIN一般分开发送。
系统调用
系统调用按照功能进行分类:
设备管理:完成设备的请求或释放,以及设备启动等功能;
文件管理:完成文件的读、写、创建及删除等功能;
进程控制:完成进程的创建、撤销、阻塞及唤醒的功能;
进程通信:完成进程之间的消息传递或信号的传递;
内存管理:完成内存的分配、回收及获取作业占用内存区大小及始址等功能。
线程和进程
进程:并发执行的程序在执行过程中分配和管理资源的基本单位。
线程:是进程的一个实体,是CPU调度和分派的基本单位。它是比进程更小的能独立运行的基本单位。一个没有线程的进程可被看作单线程。线程有时被称为轻量级进程。
线程共享的资源:进程的地址,全局变量,打开的文件,子进程,信号及信号服务程序。
线程独享的资源:程序计数器,寄存器,栈,状态字。
进程的三种基本状态及其转换,如下图:
线程与进程的区别
进程是资源分配的最小单位,线程是程序执行的最小单位。
进程有自己的独立地址空间,线程共享进程中的数据。
线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。
线程又称为轻量级进程,进程有进程控制块,线程有线程控制块。
线程必定只属于一个进程,而进程可以拥有多个线程。
线程同步
互斥锁,读写锁,自旋锁。条件变量。
进程间通信
C++常见面试题(二)
下一篇: 几个常见的链表面试题<一>