自我介绍
项目介绍
C++
-
实现多态的原理过程
-
1)编译器在发现基类中有虚函数时,会自动为每个含有虚函数的类生成一份虚表,该表是一个一维数组,虚表里保存了虚函数的入口地址
-
2)编译器会在每个对象的前四个字节中保存一个虚表指针,即vptr,指向对象所属类的虚表。在构造时,根据对象的类型去初始化虚指针vptr,从而让vptr指向正确的虚表,从而在调用虚函数时,能找到正确的函数
-
3)所谓的合适时机,在派生类定义对象时,程序运行会自动调用构造函数,在构造函数中创建虚表并对虚表初始化。在构造子类对象时,会先调用父类的构造函数,此时,编译器只“看到了”父类,并为父类对象初始化虚表指针,令它指向父类的虚表;当调用子类的构造函数时,为子类对象初始化虚表指针,令它指向子类的虚表
-
4)当派生类对基类的虚函数没有重写时,派生类的虚表指针指向的是基类的虚表;当派生类对基类的虚函数重写时,派生类的虚表指针指向的是自身的虚表;当派生类中有自己的虚函数时,在自己的虚表中将此虚函数地址添加在后面
-
这样指向派生类的基类指针在运行时,就可以根据派生类对虚函数重写情况动态的进行调用,从而实现多态性。
-
-
构造函数可以是虚函数吗?为什么?
-
(1)创建一个对象时需要确定对象的类型,而虚函数是在运行时动态确定其类型的。在构造一个对象时,由于对象还未创建成功,编译器无法知道对象的实际类型
-
(2)虚函数的调用需要虚函数表指针vptr,而该指针存放在对象的内存空间中,若构造函数声明为虚函数,那么由于对象还未创建,还没有内存空间,更没有虚函数表vtable地址用来调用虚构造函数了
-
(3)虚函数的作用在于通过父类的指针或者引用调用它的时候能够变成调用子类的那个成员函数。而构造函数是在创建对象时自动调用的,不可能通过父类或者引用去调用,因此就规定构造函数不能是虚函数
-
-
C++内存空间
- 栈
- 储存局部变量、函数参数
- 效率高但容量有限
- 堆
- 动态申请存用,就是new分配的内存
- 自由储存区
- 介于堆、栈之间
- 全局/静态储存区
- 存放全局变量和静态变量
- 常量储存区
- 放置不允许修改常量数据
- 代码区
- 存放执行代码的二进制代码
- 栈
-
new和malloc区别
- new分配内存失败抛出
bad_alloc
异常,malloc直接返回null - new分配内存是动态计算的,在自由储存区分配;而malloc需要指定大小,在堆上分配内存
- new/delete是运算符,可以重载;malloc/free是C标准库函数,不允许重载
- new/delete 封装了 malloc/free,除了分配/释放内存外,还会调用构造/析构函数
- 前者返回定义时的指针类型,后者返回void类型指针
- new分配内存失败抛出
-
常用STL容器介绍一下
-
map底层实现的结构
- 红黑树,
unordered_map
底层是哈希表
- 红黑树,
-
红黑树的特点
- 首先满足二叉排序树
- 所有节点非黑即红
- 根节点必为黑
- 红节点的子节点必为黑,但黑节点的子节点可以为黑
- 从根到NULL叶节点的任何路径上的黑节点数量相同
-
红黑树的自平衡策略?
-
(1)变色:红黑树的节点由红变黑或由黑变红
-
(2)左旋:以 某个节点作为支点(旋转支点),其右子节点变为旋转节点的父节点,右子节点的左子节点变为旋转节点的右子节点,左子节点保持不变。
-
(3)右旋:以 某个节点作为支点(旋转支点),其左子节点变为旋转节点的父节点,左子节点的右子节点变为旋转节点的左子节点,右子节点保持不变。
-
-
vector扩容
- Win+VS 1.5倍 Linux+GCC 2倍
-
C++11新特性
-
智能指针介绍
-
模版类怎么写
计算机网络
- UDP和TCP区别
-
1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
-
2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
-
3、TCP面向字节流,实际上是TCP把数据看成一连串无结构的字节流;UDP是面向报文的
UDP没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如IP电话,实时视频会议等)
-
4、每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信
-
5、TCP首部开销20字节;UDP的首部开销小,只有8个字节
-
6、TCP的逻辑通信信道是全双工的可靠信道,UDP则是不可靠信道
-
7、UDP是面向报文的,发送方的UDP对应用层交下来的报文,不合并,不拆分,只是在其上面加上首部后就交给了下面的网络层,论应用层交给UDP多长的报文,它统统发送,一次发送一个。而对接收方,接到后直接去除首部,交给上面的应用层就完成任务了。因此,它需要应用层控制报文的大小
TCP是面向字节流的,它把上面应用层交下来的数据看成无结构的字节流会发送,可以想象成流水形式的,发送方TCP会将数据放入“蓄水池”(缓存区),等到可以发送的时候就发送,不能发送就等着TCP会根据当前网络的拥塞状态来确定每个报文段的大小。
-
- 网络编程的四种IO模型
-
(1)同步阻塞IO(Blocking IO):即传统的IO模型。
-
(2)同步非阻塞IO(Non-blocking IO):默认创建的socket都是阻塞的,非阻塞IO要求socket被设置为NONBLOCK。注意这里所说的NIO并非Java的NIO(New IO)库。
-
(3)IO多路复用(IO Multiplexing):即经典的Reactor设计模式,有时也称为异步阻塞IO,Java中的Selector和Linux中的epoll都是这种模型。
-
(4)异步IO(Asynchronous IO):即经典的Proactor设计模式,也称为异步非阻塞IO。
-
- epoll ,poll和select
-
select的底层是一个fd_set的数据结构,本质上是一个long类型的数组,数组中每一个元素都对应于一个文件描述符,通过轮询所有的文件描述符来检查是否有事件发生。
优点:
1、可移植性好;
2、连接数少并且连接都十分活跃的情况下,效率也不错。缺点:
1、可以监听的最大文件描述符数量为1024(因为内核写定了)。
2、检查是否有事件发生是采用轮询遍历的方式,当文件描述符很多时开销很大。- poll和select差不多,只是poll没有最大文件描述数量限制
- epoll是一种更加高效的IO多路复用的方式,它可以监视的文件描述符数量突破了1024的限制(十万),同时不需要通过轮询遍历的方式去检查文件描述符上是否有事件发生,因为epoll_wait返回的就是有事件发生的文件描述符。本质上是事件驱动。
-
操作系统
-
多进程和多线程区别
- 同一个进程会有多个线程,线程共享该进程的内存空间
- 每一个进程是资源分配的基本单位。进程结构由以下几个部分组成:代码段、堆栈段、数据段。代码段是静态的二进制代码,多个程序可以共享。实际上在父进程创建子进程之后,父、子进程除了pid外,几乎所有的部分几乎一样。
-
pthred
和std::thread
区别- std::thread是c++标准库中的线程库,其意义在于可以跨平台不改代码
-
线程私有的数据
- 私有数据
- 栈
- 状态
- 寄存器
- 程序计数器
- 共享数据
- 全局变量
- 堆上的数据
- 函数的静态变量
- 程序代码
- 打开的文件
- 私有数据
-
gdb调试