关于网站建设外文文献,室内设计公司 网站建设,网站颜色正确搭配实例,网页制作步骤图1. 讲一讲封装、继承、多态是什么#xff1f;
封装#xff1a;将具体实现过程和数据封装成一个类#xff0c;只能通过接口进行访问#xff0c;降低耦合性#xff0c;使类成为一个具有内部数据的自我隐藏能力、功能独立的软件模块。
意义#xff1a;保护代码防止被破坏
封装将具体实现过程和数据封装成一个类只能通过接口进行访问降低耦合性使类成为一个具有内部数据的自我隐藏能力、功能独立的软件模块。
意义保护代码防止被破坏保护类中的成员通过提供的公共接口进行访问。
继承子类继承父类的特征和行为复用基类的成员数据和成员函数具有从基类复制而来的数据成员和成员函数基类私有成员可被继承但无法被访问。构造函数、析构函数、友元函数、静态数据成员、静态成员函数不能被继承。基类成员的访问方式决定派生类能否访问它们。
意义基类程序代码可被派生类复用提高软件复用效率缩短开发周期。
多态不同继承类的对象对同一消息做出不同响应基类的指针指向或绑定到派生类的对象使得基类指针呈现不同表现形式。
意义代码具有可替代性和可扩展性新增子类不影响现有类提高使用效率简化代码编写和修改过程。
2. 多态的实现原理实现方式是什么以及多态的优点特点
实现方式 动态多态通过虚函数实现编译时不确定调用哪个函数运行时确定。虚函数存在虚函数表中子类调用虚函数时通过虚表找到对应函数指针实现多态。 静态多态通过函数重载、运算符重载和重定义隐藏实现编译时确定调用哪个函数。
优点增强代码可扩展性、可替换性程序更加灵活提高使用效率简化代码编写和修改。
3. final标识符的作用是什么 类表示该类无法被继承阻止类继承。 虚函数表示该虚函数无法被重写阻止虚函数重载。
4. 虚函数是怎么实现的它存放在哪里在内存的哪个区什么时候生成的
实现原理 虚函数表存储类中所有虚函数的地址。 虚函数指针在对象内存布局中指向虚函数表动态调用虚函数。
虚函数在编译阶段生成存放在代码段虚表指针存放在对象内存布局中。
5. 智能指针的本质是什么它们的实现原理是什么
本质封装了一个原始C指针的类模板确保动态内存的安全性。
实现原理通过对象存储自动释放的资源依靠对象的析构函数释放资源。
6. 匿名函数的本质是什么他的优点是什么
本质一个对象定义时创建一个栈对象内部通过重载()符号实现函数调用。
优点免去函数的声明和定义仅在调用时创建对象调用结束后立即释放节省空间。
7. 右值引用是什么为什么要引入右值引用
右值引用为临时变量取别名绑定到临时变量或表达式上允许对右值进行修改。
引入原因 移动语义避免昂贵的复制操作实现高效的移动语义。 完美转发绑定任何类型的右值作为参数传递并转发实现完美转发。 灵活的模板编程拓展可变参数模板。
8. 左值引用和指针的区别 是否初始化指针可以不初始化引用必须初始化。 性质指针是变量引用是对象的别名。 内存单元指针有独立地址引用与对象共用一个地址。
9. 指针是什么
指针存储内存地址的变量用于访问存储在特定地址上的数据。
10. weak_ptr真的不计数是否有计数方式在哪分配的空间。
计数控制块中有强弱引用计数。 makeshared初始化控制块与sharedptr同一块空间。 new初始化控制器内存与shared_ptr不同块内存。
11. malloc的内存分配的方式有什么缺点
分配方式 brk()系统调用分配小于128KB内存堆顶指针移动获取内存free后内存缓存不归还系统。 mmap()系统调用分配大于128KB内存使用私有匿名映射分配内存free后内存归还系统。
缺点容易造成内存泄漏和碎片影响系统运行需要判断内存分配成功释放后指针需置NULL防止野指针。
11.1 为什么不全部使用mmap来分配内存
原因系统调用耗时频繁切换状态影响效率。mmap分配的内存每次释放归还系统触发缺页中断。
11.2 为什么不全部都用brk
原因频繁调用malloc和free产生内存碎片影响效率。
12. 传入一个指针它如何确定具体要清理多少空间呢
申请内存时多分配16字节保存内存块详细信息free时对内存地址左偏移16字节分析内存块大小。
13. define和const的区别是什么 编译阶段define在编译预处理阶段简单文本替换const在编译阶段确定值。 安全性define没有数据类型无类型检查const有类型检查。 内存占用define宏常量多次替换占用多个备份const常量占用静态存储区域空间。 调试define宏常量不能调试const常量可调试。
14. 程序运行的步骤是什么 预编译头文件编译宏替换输出.i文件。 编译转化为汇编语言文件词法分析语义分析错误检查生成.s文件。 汇编汇编器翻译为机器语言生成.o文件。 链接目标文件和库链接生成可执行文件.exe。
15. 锁的底层原理是什么
底层原理通过CAS和atomic机制实现。 CAS机制比较相同再交换确保原子操作。 atomic机制提供原子操作。
16. 原子操作是什么
原子操作不会被线程调度打断的操作执行期间不会切换线程。 原理CPU提供对总线加锁手段指令前加LOCK前缀锁住总线保证原子性。
17. class与struct的区别 继承权限class默认private继承struct默认public继承。 模板参数class用于定义模板参数struct不能定义模板参数C保留struct兼容C语言。
18. 内存对齐是什么为什么要进行内存对齐内存对齐有什么好处
内存对齐处理器为提高性能对存取数据起始地址的要求。 原因不同硬件平台具有差异性内存对齐提高平台移植性。 好处减少内存访问次数提高性能增强程序可移植性。
19. 进程之间的通信方式有哪些 管道匿名管道和命名管道半双工通信适合简单通信。 消息队列边发边收消息长度和总数量有限。 共享内存解决内核态和用户态数据拷贝问题。 信号量实现进程间互斥和同步。 信号 套接字
20. 线程之间的通信方式有哪些 信号量 条件变量 互斥量
21. 介绍一下socket中的多路复用及其他们的优缺点epoll的水平和边缘触发模式
IO多路复用select、poll、epoll都是IO多路复用机制可以监视多个文件描述符一旦某个文件描述符进入读或写就绪状态系统就能进行相应的读写操作。
Select
优点 可移植性好因为在某些Unix系统中并不支持poll和epoll。 对于超时时间提供了更好的精度微秒而poll和epoll都是毫秒级。
缺点 支持监听的文件描述符fd的数量有限制最大数量默认是1024个。 需要维护一个用来存放文件描述符的数据结构每次调用select都需要把fd集合从用户区拷贝到内核区select系统调用后有需要把fd集合从内核区拷贝到用户区这个系统开销在fd数量很多的时候会很大。
Poll
优点 没有最大文件描述符数量的限制poll基于链表存储主要解决了文件描述符数量的限制问题。 优化了编程接口减少了函数调用参数。
缺点
与select一样需要维护一个用来存放文件描述符的数据结构当注册的文件描述符数量很多时会使得用户态和内核区之间传递该数据结构的复制开销很大。
Epoll
优点 没有最大文件描述符数量的限制。 只需要将文件描述符数据结构拷贝一次不需要重复拷贝在调用epollctl系统调用时拷贝一次要监听的文件描述符数据结构到内核区在调用epollwait时不需要再重复拷贝。 提供水平触发和边缘触发两种模式。
缺点
目前只有Linux操作系统支持epoll不支持跨平台使用而Unix操作系统上是使用kqueue。
Epoll的触发模式
水平触发LT 对于读操作只要缓冲区内容不为空LT模式返回读就绪。 对于写操作只要缓冲区还不满LT模式返回写就绪。
边缘触发ET 对于读操作当缓冲区由不可读变为可读的时候进程会被唤醒缓冲区数据变少时不会再次唤醒进程。 当被监控的文件描述符上有可读写事件发生时epoll_wait()会通知处理程序去读写。如果这次没有把数据全部读写完ET模式下不会再次通知直到出现第二次可读写事件。
22. 什么是重载、重写、隐藏
重载函数名相同参数不同处于同一作用域。
重写子类和父类中函数名、返回值、参数相同必须为虚函数。
隐藏子类实现了一个与父类同名的函数隐藏父类同名函数。
23. 什么是this指针为什么存在this指针
this指针指向调用成员函数的当前对象的指针。
原因类和对象的成员函数存储在公共代码段不同对象调用成员函数时编译器通过 this 指针知道具体操作的对象。
24. 类的生命周期
类从被加载到内存中开始到卸载出内存为止它的整个生命周期包括加载、验证、准备、解析、初始化、使用和卸载七个阶段。其中验证准备解析三个部分统称为连接。 全局对象在main开始前被创建main退出后被销毁。 静态对象在第一次进入作用域时被创建在main退出后被销毁。 局部对象在进入作用域时被创建在退出作用域时被销毁。 new创建的对象直到内存被释放的时候都存在。
25. 父类的构造函数和析构函数是否能为虚函数这样操作导致的结果 构造函数不能为虚函数因为虚函数表由类的实例化对象的vptr指针指向该指针存放在对象内部空间中需要调用构造函数完成初始化如果构造函数为虚函数调用构造函数时vptr还未初始化导致无法构造对象。 析构函数可以且经常为虚函数当使用父类指针指向子类时调用析构函数只会调用父类的析构函数子类的析构函数不会被调用容易造成内存泄漏。
26. 多线程为什么会发生死锁死锁是什么死锁产生的条件如何解决死锁
死锁在多进程中易发生多进程对资源的竞争如果一个进程集合中的每个进程都在等待集合中的其他一个进程才能继续执行若无外力他们将无法推进这种情况就是死锁。
产生死锁的四个条件 互斥条件 请求和保持条件 不可剥夺条件 环路等待条件
解决死锁的方法
破坏上述任意一种条件。
27. 描述一下面向过程和面向对象
面向对象 将问题分解为各个对象建立对象的目的是描述某个事物在解决问题步骤中的行为。 代码更易维护和复用但代码效率相对较低。
面向过程 分析问题的步骤然后一步步实现使用时按顺序调用即可。 代码效率高但复用率低不易维护。
28. C中左值和右值是什么i是左值还是右值i和i哪个效率更高
左值指表达式结束后依然存在的值。 右值指表达式结束后不再存在的值。
i是左值因为它返回自身i是右值因为它返回一个临时变量。
效率i更高因为i直接对变量进行自增操作而i会产生一个临时变量保存旧值。
29. 介绍一下vector、list的底层实现原理和优缺点
Vector 优点可使用下标随机访问尾插尾删效率高。 缺点前面部分的插入删除效率低扩容有消耗可能存在一定的空间浪费。 底层由连续的内存空间组成由头指针、尾指针和可用空间尾指针实现。
List 优点按需申请内存不需要扩容不会造成内存空间浪费。任意位置插入删除效率高。 缺点不支持下标随机访问。 底层由双向链表实现。
30. 静态变量在哪里初始化在哪一个阶段初始化
静态变量、全局变量、常量在编译阶段完成初始化和内存分配存放在全局区域。
31. 如何实现多进程 Linux使用fork函数创建进程。 Windows使用CreateProcess函数创建进程。
32. 空对象指针为什么能调用函数
在类初始化时编译器将函数分配到类的外部包括静态成员函数。调用类中的成员函数时如果不使用类中的任何成员变量不会使用到this指针所以可以正常调用。
33. shared_ptr线程安全吗
智能指针中的引用计数是线程安全的但智能指针指向的对象线程安全问题不保障。智能指针管理资源的生命周期是线程安全的但资源的访问不是线程安全的。
34. push_back()左值和右值的区别是什么 左值使用拷贝构造新对象。 右值使用移动构造新对象。
35. move底层是怎么实现的
move功能将一个左值引用强制转化为右值引用使用右值引用实现移动语义避免拷贝构造将对象状态所有权从一个对象转移到另一个对象没有内存搬迁或内存拷贝。
36. 完美转发的原理是什么
完美转发函数模板可以将参数完美转发给内部调用的其他函数不仅能转发参数的值还能保持参数的左、右值属性不变。使用引用折叠规则将传递进来的左值以左值传递将右值以右值传递。
37. 空类中有什么函数 默认构造函数 默认拷贝构造函数 默认析构函数 默认赋值运算符 取值运算符 const取值运算符
38. explicit用在哪里有什么作用
explicit只能用于修饰只有一个参数的类构造函数当其他参数有默认值时也有效表示该构造函数是显式的防止隐式转换。
39. 成员变量初始化的顺序是什么 成员变量在使用初始化列表初始化时与构造函数中初始化成员列表的顺序无关只与定义成员变量的顺序有关。 不使用初始化列表时与构造函数内的顺序有关。 const成员必须在初始化列表中初始化。 static成员变量只能在类外初始化。
顺序 基类静态变量或全局变量 派生类静态变量或全局变量 基类成员变量 派生类成员变量
40. 指针占用的大小是多少 64位系统8字节 32位系统4字节
计算机的位数指CPU一次性处理、传输、保存的信息的最大长度。CPU访问内存的地址由位数决定因此指针的大小取决于系统的位数。
41. 野指针和内存泄漏是什么如何避免
内存泄漏指程序中动态分配的堆内存由于未释放或无法释放造成系统内存的浪费可能导致程序运行速度减慢甚至系统崩溃。
避免方法 使用智能指针管理资源。 在释放对象数组时使用 delete[]。 尽量避免在堆上分配内存。
野指针指向一个已删除对象或未申请访问受限内存区域的指针。
避免方法 对指针进行初始化。 用合法的可访问内存地址对指针初始化。 指针用完释放内存将指针赋值为 nullptr。
42. malloc和new的区别是什么 类型malloc/free 是标准库函数new/delete 是 C 运算符。 失败处理malloc 分配内存失败返回 NULLnew 失败抛异常。 构造和析构new/delete 会调用构造和析构函数malloc/free 不会。 返回类型new 返回有类型的指针malloc 返回无类型的指针。 内存位置malloc 从堆上分配内存new 从自由存储区分配内存依赖于 operator new 的实现。
43. 多线程会发生什么问题线程同步有哪些手段
问题 资源竞争。 频繁上锁导致程序效率低下。 死锁。
线程同步手段 使用 atomic 原子变量。 使用互斥量上锁。 使用条件变量或信号量制约对共享资源的并发访问。
44. 什么是STL
STL 是 C 标准库的重要组成部分不仅是一个可复用的组件库也是一个包含数据结构与算法的软件架构。STL 拥有六大组件仿函数、算法、迭代器、空间配置器、容器、配接器。
45. 对比迭代器和指针的区别 迭代器不是指针是一个模板类通过重载指针的一些操作符模拟指针功能迭代器返回的是对象引用而不是对象的值。 指针能够指向函数而迭代器不行迭代器只能指向容器。
46. 线程有哪些状态线程锁有哪些
线程状态创建、就绪、运行、阻塞、死亡。
线程锁的种类互斥锁、条件锁、自旋锁、读写锁、递归锁。
47. 解释说明一下map和unordered_map map内部实现是红黑树所有元素有序。 unordered_map内部实现是哈希表元素无序。
优缺点 map 优点有序红黑树实现的操作复杂度为 O(log n)效率高。 缺点空间占用率高。 unordered_map 优点查找效率高。 缺点哈希表建立比较费时间。
48. vector中的pushback()和emplaceback()的区别、以及使用场景 push_back()调用类的有参构造函数创建一个临时变量再将元素拷贝或移动到容器中。 emplace_back()直接在容器尾部构造元素少一次构造函数调用。
使用场景 emplace_back()用于直接在容器中构造新元素。 push_back()用于将现有对象添加到容器中。
49. 如何实现线程安全除了加锁还有没有其他的方式
除了锁之外还可以使用 互斥量防止多个线程同时访问共享资源避免数据竞争。 原子操作确保多线程环境中操作的安全性。 条件变量协调线程之间的协作用于在线程之间传递信号控制线程的执行流程。
50. vector扩容resize和reserve的区别 resize改变 vector 的大小size可能会添加或删除元素。 reserve改变 vector 的容量capacity不改变当前元素的数量仅优化内存使用和性能。
51. vector扩容为了避免重复扩容做了哪些机制 当 vector 内存不够时本身内存会以1.5倍或者2倍的增长以减少扩容次数。 引入了 reserve 方法自定义 vector 最大容量。
52. C中空类的大小是多少
1字节。
53. weak_ptr是怎么实现的
实现依赖于计数器和寄存器。计数器记录弱引用的数量寄存器存储 shared_ptr。
54. 虚函数的底层原理是什么
虚函数的底层原理是虚函数表和虚表指针。
55. 一个函数f(int a, int b)其中a和b的地址关系是什么
a和b的地址是相邻的。
56. 移动构造和拷贝构造的区别是什么 移动构造基于指针的拷贝实现对堆区内存所有权的移交减少不必要的拷贝。 拷贝构造将传入的对象复制一份然后放进新的内存中。
57. lamda表达式捕获列表捕获的方式有哪些如果是引用捕获要注意什么 捕获方式按值捕获和引用捕获。 注意事项默认的引用捕获可能会导致悬挂引用闭包包含局部变量的引用或形参的引用如果闭包生命周期超过了局部变量或形参的生命期引用将会空悬。解决方法是对个别参数使用值捕获。
58. 哈希碰撞的处理方法 开放定址法遇到哈希冲突时寻找新的空闲哈希地址。 再哈希法构造多个哈希函数发生冲突时使用其他哈希函数。 链地址法将所有哈希地址相同的记录链接在同一链表中。 建立公共溢出区将哈希表分为基本表和溢出表将冲突的记录存放在溢出表中。
59. unordered_map的扩容过程
当 unordered_map 中的元素数量达到桶的负载因子通常是0.75时会重新分配桶的数量通常按原有桶数量的2倍进行扩容并将所有元素重新哈希到新的桶中。
60. vector如何判断应该扩容size和capacity
通过当前容器内元素数量size和容器最大大小capacity进行比较如果二者相等vector 会进行扩容一般为1.5倍部分情况下为2倍。
61. 构造函数是否能声明为虚函数为什么什么情况下为错误
构造函数不能为虚函数。虚函数的调用是通过虚函数表来查找的而虚函数表由类的实例化对象的vptr指针指向该指针存放在对象的内部空间之中。调用构造函数时vptr 还没有初始化因此无法找到虚函数表导致无法构造对象。
62. 类中 static 函数是否能声明为虚函数
不能。类中的 static 函数是所有类实例化对象所共有的没有 this 指针而虚函数依靠 vptr 和 vtable 来处理。vptr 是一个指针在类的构造函数中生成并且只能通过 this 指针访问。对于静态成员函数来说没有 this 指针无法访问 vptr因此 static 函数无法声明为虚函数。
63. 哪些函数不能被声明为虚函数 构造函数 内联函数内联函数在编译时展开没有 this 指针 静态成员函数 友元函数C 不支持友元函数的继承 非类成员函数
64. 如何保证类的对象只能被开辟在堆上将构造函数声明为私有、单例
将构造函数设置为私有这样只能使用 new 运算符来创建对象。需要准备一个 destroy 函数来进行内存的释放然后将析构函数设置为 protected提供一个 public 的 static 函数来完成构造类似于单例模式。
如果需要在栈上分配可以重载 new 操作符使得 new 操作符功能为空这样外部程序无法在堆上分配对象只能在栈上分配。
65. 讲讲你理解的虚基类
虚基类是 C 中一种特殊的类用于解决多继承所带来的“菱形继承”问题。如果一个派生类同时从两个基类派生而这两个基类又共同继承自同一个虚基类就会形成“菱形”继承结构导致派生类中存在两份共同继承的虚基类的实例从而引发问题。
虚继承会使得派生类中只存在一份共同继承的虚基类实例避免多个实例之间的冲突。虚基类可以被实例化。
66. C哪些运算符不能被重载 成员访问操作符 . 域解析操作符 :: 条件运算符 ?: sizeof 运算符 typeid 运算符
不推荐重载的运算符逗号运算符、逻辑或逻辑与运算符容易造成歧义。
67. 动态链接和静态链接的区别动态链接的原理是什么
区别 静态链接在形成可执行程序前进行。将库中的代码包含到自己的程序中每个程序链接静态库后都会包含一份独立的代码运行时所有这些重复的代码占用独立的存储空间浪费资源。 动态链接程序执行时进行不将代码直接复制到自己程序中只留下调用接口运行时加载动态库所有程序共享一份动态库因此动态库也称为共享库。
动态链接原理 将程序按照模块拆分成各个相对独立部分程序运行时将它们链接在一起形成完整的程序而不是像静态链接那样将所有模块都链接成一个单独的可执行文件。
68. C中怎么编译C语言代码
使用 extern C 让 C 代码按照 C 语言的方式编译。
69. 未初始化的全局变量和初始化的全局变量放在哪里 初始化的全局变量存放在数据段数据段数据静态分配。 未初始化的全局变量存放在 BSS 段Block Started By Symbol属于静态内存分配。
70. 说一下内联函数及其优缺点
内联函数在编译期将函数体内嵌到程序中以节省函数调用的开销。
优点节省函数调用开销使程序运行更快。
缺点函数体过长时频繁使用内联函数会导致代码膨胀问题不能递归执行。
71. C11中的auto是怎么实现自动识别类型的模板是怎样实现转化成不同类型的
auto在编译期间被真正的类型替代编译器推导出变量的类型。C 中变量必须有明确类型auto 是由编译器推导出来的。
模板函数模板是一个蓝图本身不是函数是编译器用来生成具体类型函数的模具。模板将原本应该由程序员做的重复工作交给编译器。
72. map和set的区别和底层实现是什么map取值的find[]at方法的区别(at有越界检查功能)
map和set区别 map键值对允许通过键访问值。 set只存储键没有值。
底层实现都是红黑树。
取值方法区别 find返回迭代器需判断返回结果才能确定是否找到。 []如果键不存在则插入如果存在则覆盖返回值。 at进行越界检查如果键不存在则抛出异常。
73. 详细说一说fcntl的作用
作用用于控制打开的文件描述符的属性和行为。
功能 复制一个现有的描述符cmdF_DUPFD。 获得/设置文件描述符标记cmdFGETFD或FSETFD。 获取/设置文件状态标记cmdFGETFL或FSETFL。 获取/设置异步IO所有权cmdFGETOWN或FSETOWN。 获取/设置记录锁cmdFGETLK或FSETLK。
74. C的面向对象主要体现在那些方面
C 的面向对象体现在引入了封装、继承、多态的特性。 封装隐藏对象的实现细节只暴露接口。 继承通过继承关系复用代码构建类的层次结构。 多态通过虚函数实现不同对象对同一消息的不同响应提高代码灵活性和可扩展性。
75. 介绍一下extern C关键字为什么会有这个关键字
extern C 用于在 C 代码中按照 C 语言的方式编译代码。C 为了兼容 C 语言而引入这个关键字使得 C 编译器能够识别并正确处理 C 语言函数。
76. 讲一讲迭代器失效及其解决方法
迭代器失效当容器的结构发生变化如插入、删除元素时原有的迭代器可能会变得无效。
解决方法 序列式容器vector、deque、list vector插入元素时如果空间未重新分配指向插入位置之前的迭代器有效之后的迭代器失效。删除元素时指向删除位置之后的迭代器失效。使用 erase 返回的迭代器继续操作。 deque插入到首尾位置之外的任意位置都会导致迭代器失效。如果在首尾位置添加元素迭代器失效但指针和引用有效。 list插入或删除元素时不影响其他迭代器。 关联型容器map、set map、set删除当前元素的迭代器失效其他迭代器仍然有效。
77. 编译器是如何实现重载的
编译器遇到函数时在符号表中命名一个符号存放函数地址。如果函数定义在使用之前编译符号表直接存储函数地址。C 语言中符号表以函数名存储函数地址函数名相同的重载函数地址会冲突。C 中符号表符号是函数名加参数等属性避免了重载函数的查询歧义。
78. 什么是函数调用约定
函数调用约定是对函数调用的约束和规定描述函数参数的传递方式和栈指针的恢复方式。
常见约定
__stdcall参数从右到左入
栈被调用函数清理堆栈返回值在 EAX 中。 __cdecl参数从右到左入栈调用者清理堆栈返回值在 EAX 中允许可变参数函数存在。 __fastcall前两个双字参数通过寄存器传递其余参数从右到左压栈被调用函数清理堆栈返回值在 EAX 中。 __thiscall用于 C 类成员函数调用this 指针通过 ECX 传递参数从右到左入栈调用者清理堆栈。 __pascal与 __stdcall 类似已废弃。
79. 使用条件变量的时候需要注意什么 signal先于wait时信号会丢失wait 和 signal 操作需要加锁确保原子性。 生产者在生产资源和 cond signal 时加锁确保 cond wait 和 cond signal 的先后顺序正确避免丢失信号。
80. 类内普通成员函数可以调用类内静态变量吗类内静态成员函数可以访问类内普通变量吗 普通成员函数可以调用静态变量静态变量在编译时已初始化和分配内存普通成员函数可以访问。 静态成员函数不能直接访问普通变量静态函数没有 this 指针不能直接访问非静态变量但可以通过类实例化对象访问非静态成员变量。
81. 强制类型转换有哪几种类型分别有什么特点原理是什么
1. static_cast 特点 用于数据类型的强制转换。 在类层次结构中基类和派生类之间的指针或引用转换。 用于基本类型之间的转换如 int 转 char。 将空指针转换成目标类型的空指针。 将任意类型的表达式转换成 void 类型。 原理在编译期间进行转换没有运行时检查不改变表达式的 const、volatile、__unaligned 属性。
2. const_cast 特点 用于去除 const、volatile 属性。 常量指针转换为非常量指针指向原来的对象。 常量引用转换为非常量引用指向原来的对象。 常量对象转换成非常量对象。 原理用于去除指针或引用的常量性不用于基本数据类型的转换。
3. reinterpret_cast 特点 用于改变指针或引用的类型。 将指针或引用类型转换为足够长的整数或将整数转换为指针或引用。 传入类型必须是指针、引用、算术类型、函数指针、成员函数或成员指针。 原理在内存中直接进行比特位拷贝转换后指向相同的内存地址。
4. dynamic_cast 特点 运行时处理进行类型检查。 用于类层次结构中基类和派生类之间的指针或引用转换。 不能用于内置基本数据类型。 转换成功返回指向类的指针或引用失败返回 NULL 或抛出 std::bad_cast 异常。 基类中必须有虚函数。 原理通过运行时类型信息RTTI进行类型检查和转换。
82. 回调函数是什么为什么要有回调函数有什么优缺点回调的本质是什么
回调函数使用者定义一个函数由其他函数在特定事件发生时调用。即将一个函数作为参数传入另一个函数由后者在运行时调用。
优点 调用者和被调用者分离提高模块化和可复用性。 实现多种处理方式和操作。 隐藏耗时操作提高主程序效率。 使代码逻辑集中易于阅读和维护。
缺点 回调函数过多会导致代码难以维护。 资源竞争共享资源访问容易出现争抢导致程序出错。 可读性差可能破坏代码结构和可读性。
本质将函数作为参数使用使程序更加灵活和普适。
83. Linux中的信号有哪些 SIGINT终端中断符CtrlC默认动作终止。 SIGQUIT终端退出符Ctrl\默认动作终止并生成core文件。 SIGILL非法硬件指令默认动作终止并生成core文件。 SIGABRT进程中止默认动作终止并生成core文件。 SIGFPE算术运算错误默认动作终止并生成core文件。 SIGKILL强制终止默认动作终止无法捕捉和忽略。 SIGSEGV无效内存引用默认动作终止并生成core文件。 SIGALRM定时器超时默认动作终止。 SIGTERM终止默认动作终止可以被捕捉和处理。 SIGCONT使暂停进程继续默认动作忽略。 SIGURG紧急情况默认动作忽略。 SIGPOLL/SIGIO可轮询事件/异步IO默认动作终止。
84. 什么是尾递归
尾递归递归函数在尾部直接调用自身的递归函数。
原理编译器检测到尾递归调用时会覆盖当前的活动记录而不是在栈中创建新的记录减少栈空间使用提高运行效率。
特点在尾部调用自身通过优化使计算仅占用常量栈空间。
85. 为什么会有栈溢出为什么栈会设置容量
栈溢出函数嵌套调用过多或定义局部变量过大超过了预设的栈空间大小。
原因 栈的地址空间必须连续任其无限增长会给内存管理带来困难。 多线程程序每个线程需要分配栈栈容量不能设置过大。
86. 二叉树和平衡二叉树的区别 二叉树没有平衡因子的限制可能退化为链表。 平衡二叉树有平衡因子限制保持平衡不会退化为链表。
87. 平衡二叉树的优缺点
优点避免二叉树退化为链表平均查找时间复杂度为 O(log N)。
缺点插入和删除操作需要维护平衡旋转操作较多性能较低。
88. 静态成员函数可以是虚函数吗为什么
静态成员函数不能是虚函数。静态成员函数属于类的共有函数不依赖于对象调用没有 this 指针无法放进虚函数表。
89. 构造函数可以为虚函数吗为什么
构造函数不能为虚函数。虚表指针存储在对象的内存空间调用虚函数时通过虚表指针查找虚函数表。而构造函数实例化对象定义为虚函数时对象还没有实例化没有虚表指针无法调用构造函数。
90. make_shared函数的优点缺点
优点 减少内存分配次数降低系统开销提高效率。 使用 new 构造至少需要两次内存分配make_shared 只需一次。
缺点 当构造函数是保护或私有时无法使用 make_shared。 weakptr 保持控制块生命周期只有最后一个 weakptr 离开作用域时内存才释放对内存要求高的场景需注意。
91. 函数调用进行的操作 将参数压栈按照参数顺序的逆序进行如果参数中有对象则先进行拷贝构造。 保存返回地址即函数调用结束返回后接着执行的语句的地址。 保护维护函数栈帧信息的寄存器内容如SP堆栈指针FP栈帧指针等。 保存一些通用寄存器的内容因为有些通用寄存器会被所有函数用到所以在函数调用之前这些寄存器可能已经放置了对函数有用的信息。 调用函数函数执行完毕。 恢复通用寄存器的值。 恢复保存函数栈帧信息的那些寄存器的值。 通过移动栈指针销毁函数的栈帧。 将保存的返回地址出栈并赋给寄存器。 通过移动栈指针回收传给函数的参数所占用的空间。