一、C++基础概念

1. 值传递和引用传递的区别
值传递是将实参的值拷贝一份给形参,函数内对形参的修改不影响实参。引用传递是将实参的别名传给形参,对形参的修改直接作用于实参,避免了拷贝开销。

2. C和C++的区别
C是面向过程的语言,C++是面向对象的语言,支持类、继承、多态。C++引入了异常处理、模板、STL、函数重载等特性,内存管理上C++有new/delete和智能指针。

3. C++的编译过程
预处理(宏展开、头文件包含)→编译(生成汇编代码)→汇编(生成目标文件)→链接(合并目标文件和库)。

4. 动态链接和静态链接
静态链接将库代码复制到可执行文件中,体积大但独立运行。动态链接在运行时加载共享库,节省内存和磁盘空间,便于更新。

5. 左值和右值
左值是可以取地址的表达式(如变量名),右值是不能取地址的临时对象或字面值(如10、函数返回值)。C++11中右值又分为纯右值和将亡值。

6. 移动语义和完美转发
移动语义通过转移资源所有权避免深拷贝,提高性能。完美转发通过std::forward保持参数在传递过程中的左/右值属性。

7. 列表初始化
使用花括号{}初始化对象,可以防止窄化转换,支持初始化任意类型。

8. move有什么作用,原理是什么
std::move将左值强制转换为右值引用,触发移动语义。原理是返回一个右值引用类型static_cast<T&&>(arg),实际不移动任何东西,只是类型转换。

9. C++的三种智能指针
unique_ptr独占所有权,禁止拷贝;shared_ptr共享所有权,使用引用计数;weak_ptr配合shared_ptr使用,解决循环引用,不增加计数。

10. C++11中有哪些常用的新特性
auto类型推导、范围for循环、智能指针、移动语义、完美转发、lambda表达式、nullptr、constexpr、列表初始化、右值引用、可变参数模板、线程库等。

11. static的作用以及场景
修饰全局变量/函数:限制作用域在当前文件;修饰局部变量:延长生命周期至程序结束;修饰类成员变量:所有对象共享;修饰类成员函数:无this指针,只能访问静态成员。

12. const
修饰变量表示只读不可修改;修饰指针分常量指针和指针常量;修饰函数参数表示不修改实参;修饰成员函数表示不修改成员变量。

13. define和const的区别
define是预处理宏替换,无类型检查;const是编译期常量,有类型检查,占用内存。

14. char,const char,char const,const char const的区别**
char:可修改指向的字符和指向;const char:可修改指向,不能修改字符内容;char* const:不能修改指向,可修改字符;const char* const:都不能修改。

15. inline
建议编译器将函数内联展开,减少函数调用开销,适用于频繁调用的短小函数。只是建议,最终由编译器决定。

16. 数组和指针的区别
数组名是常量指针,不可修改;指针可以重新指向。sizeof数组得数组大小,sizeof指针得指针本身大小(4/8字节)。

17. sizeof和strlen
sizeof是运算符,编译时计算,包括'\0';strlen是函数,运行时计算,遇到'\0'停止,不包括'\0'。

18. extern有什么作用?extern"C"有什么作用?
extern声明变量或函数在其他文件中定义。extern"C"告诉编译器按C的方式编译,防止名字修饰,用于C++调用C库。

19. explicit的作用
防止构造函数进行隐式类型转换,只能显式调用。

20. final关键字的作用
修饰类:禁止该类被继承;修饰虚函数:禁止子类重写该函数。

21. push_back和emplace_back
push_back传入对象或临时对象,可能触发拷贝或移动构造;emplace_back直接传入构造参数,在容器内原地构造对象,避免临时对象创建,效率更高。

22. 野指针和悬挂指针的区别
野指针未初始化,指向随机内存;悬挂指针指向已释放的内存。两者都是非法访问。

23. 内存对齐是什么?为什么要内存对齐?
内存对齐是数据在内存中按特定字节倍数存放。原因:硬件平台要求、提高CPU访问效率、减少缓存行失效。

24. 如何解决内存碎片?页合并怎么做?
使用内存池、对象池减少频繁分配释放。页合并在操作系统层面,将物理地址连续的多个小页合并成大页,减少TLB miss。

25. 如何检测内存泄漏?如何实现一个内存泄漏检测工具?
使用valgrind、AddressSanitizer等工具。实现原理:重载new/delete,记录分配信息和调用栈,程序退出时检查未释放的内存。

26. ECS架构为什么能优化性能?
数据连续存储,提高缓存命中率;逻辑与数据分离,便于并行处理;避免虚函数调用,提高CPU指令缓存效率。

27. 对象池的优化原理,配合LRU/LFU淘汰机制怎么做?
预分配一批对象重复使用,减少分配释放开销。LRU淘汰最近最少使用的对象,LFU淘汰最不常使用的对象,可用链表+哈希表实现。

28. 四种类型转换的使用场景
const_cast去除const属性;static_cast基础类型转换、父子类指针转换(无运行时检查);dynamic_cast多态类型安全转换(需要RTTI);reinterpret_cast任意指针类型转换,最不安全。

29. volatile关键字的作用
告诉编译器该变量可能被意外修改(如多线程、硬件寄存器),禁止优化,每次都从内存读取。

二、面向对象与多态

30. 多态
多态分为静态多态(函数重载、模板)和动态多态(虚函数)。动态多态允许通过基类指针或引用调用派生类的重写函数。

31. 介绍一下虚函数,虚函数表是在什么时候生成的?
虚函数允许子类重写父类方法,实现动态绑定。虚函数表在编译阶段生成,存储在只读数据段,每个包含虚函数的类都有一个虚表。

32. 构造函数可以是虚函数吗?析构函数一定要是虚函数吗?
构造函数不能是虚函数(虚表未完全建立)。基类析构函数一般声明为虚函数,确保通过基类指针删除派生类对象时正确调用派生类析构,避免内存泄漏。

33. 内联函数可以是虚函数吗?
可以,但呈现多态时(通过基类指针调用)内联失效;通过对象直接调用时可能内联。

34. 什么场景下需要用到移动构造函数和移动赋值运算符?
类管理动态资源(如指针、文件句柄)时,避免不必要的深拷贝,提高性能。

35. 堆与栈的区别?为什么栈效率更高?
堆手动分配释放,大小灵活但速度慢;栈自动分配释放,连续内存,速度快。栈效率高因为分配释放只需移动栈指针,缓存命中率高。

36. 虚继承
解决菱形继承中的二义性和数据冗余问题,子类共享同一个基类实例。

37. 函数重载是什么?优点是什么?和重写有什么区别?
重载:同一作用域内函数名相同参数不同(类型/个数),编译期决定。重写:派生类重新定义基类虚函数,运行时决定。

38. 运算符重载
为自定义类型定义运算符行为,如+、-、[]等,使对象使用像内置类型一样自然。

39. struct和union的区别?如何使用union做优化?
struct所有成员共存,union所有成员共享同一块内存,大小取最大成员。union用于节省内存、实现类型双关、解析协议数据。

40. using和typedef的区别
using可定义别名,语法更直观,支持模板别名;typedef只能定义简单类型别名。

41. enum和enum class的区别?
enum无作用域,隐式转为int;enum class有作用域,强类型,不会隐式转换,更安全。

三、内存管理

42. new和malloc的区别?
new是运算符,自动计算大小,调用构造函数;malloc是函数,需手动指定大小,不调用构造函数。

43. new 出来的对象可以用 free 释放吗?
不行。free不会调用析构函数,可能导致资源泄漏;new和delete必须成对使用。

44. delete和free的区别?delete和free的区别?
delete调用析构函数再释放内存;free仅释放内存。

45. delete关键字和default关键字的作用?
=delete禁止生成默认函数;=default显式要求编译器生成默认版本。

46. this指针的作用?
指向当前对象本身,在成员函数中访问成员变量,解决名称冲突。

47. C++中可以用delete this吗?
可以,但要确保对象是用new创建的,且之后不再使用this指针。

48. vector的原理是什么?resize和reserve的区别是什么?size和capacity的区别?
vector动态数组,连续内存存储。resize改变size(可能构造/析构元素);reserve只改变capacity,预分配内存。size是实际元素个数;capacity是已分配内存能容纳的元素个数。

49. vector扩容机制是什么?如何增删元素,用iterator有什么问题?
容量不足时重新分配更大内存(通常1.5或2倍),移动旧元素。插入删除可能导致迭代器失效(重新分配或元素移动后)。

50. deque
双端队列,分段连续内存存储,支持首尾高效插入删除,中间插入删除慢。

51. map和unordered_map
map红黑树实现,有序,O(logn);unordered_map哈希表实现,无序,平均O(1)。

52. map与hashmap的区别
C++标准库没有hashmap,unordered_map类似哈希表。map有序,unordered_map无序。

53. 哈希冲突的解决
开放定址法、链地址法(常用,如unordered_map)、再哈希法、公共溢出区。

54. Friend关键字
友元函数或类可以访问另一个类的私有成员,破坏封装,但某些场景必要。

55. list
双向链表,非连续存储,插入删除快但不支持随机访问。

56. RAII
资源获取即初始化,构造函数获取资源,析构函数释放资源,确保异常安全。

57. lock_guard和unique_lock的区别
lock_guard简单RAII包装,构造加锁析构解锁,不可手动控制;unique_lock更灵活,可手动lock/unlock,支持延迟锁、超时等。

58. thread的join和detach的区别
join等待线程结束并回收资源;detach分离线程,让其后台运行,资源在线程结束时自动回收。

59. jthread和thread的区别
C++20引入,支持自动join和停止请求,析构时自动join,避免手动处理。

60. memcpy和memmove的区别
memcpy假设内存不重叠,memmove处理重叠情况,更安全。

四、模板与泛型

61. 请介绍C++中使用模板的优缺点?
优点:代码复用、类型安全、性能高(编译期生成);缺点:编译时间长、代码膨胀、错误信息难读。

62. C++中函数模板和类模板有什么区别?
函数模板用于生成函数,参数类型推导;类模板用于生成类,需显式指定类型参数。

63. 请介绍下C++模板中的SFINAE?它的原则是什么?
替换失败不是错误。模板匹配时,若某个特化的替换导致非法代码,编译器不会报错,而是尝试其他匹配。

64. C++的strcpy和memcpy有什么区别?
strcpy拷贝字符串直到遇到'\0';memcpy拷贝指定长度内存,不关心内容。

65. C++中为什么要使用std::array?它有什么优点?
固定大小数组,封装了C风格数组,提供STL接口,安全,可拷贝,不退化指针。

66. C++中堆内存和栈内存的区别?
同35题。

67. C++的栈溢出是什么?
栈空间耗尽,常见于无限递归、超大局部数组。程序崩溃。

68. 什么是C++的回调函数?为什么需要回调函数?
通过函数指针传递的函数,在特定事件发生时调用。用于解耦、实现异步处理、事件驱动。

69. C++中为什么要使用nullptr而不是NULL?
nullptr是类型安全的指针空值,可转为任意指针类型;NULL是整数0,可能导致重载歧义。

70. 什么是大端序?什么是小端序?
大端序高位字节存低地址,小端序低位字节存低地址。网络协议常用大端,x86常用小端。

71. C++中include<a.h>和include"a.h"有什么区别?
<>搜索系统头文件目录," "先搜索当前目录再搜索系统目录。

72. C++是否可以include源文件?
可以但不推荐,可能导致重复定义、编译混乱。

73. 什么是深拷贝?什么是浅拷贝?写一个标准的拷贝构造函数?
浅拷贝复制指针值,多个对象指向同一内存;深拷贝复制指针指向的内容,独立内存。标准拷贝构造:对成员逐个深拷贝。

74. 命名空间有什么作用?如何使用?
防止命名冲突,组织代码。使用using namespace或作用域运算符::访问。

75. 友元类和友元函数有什么作用?
允许外部函数或类访问本类的私有成员。

76. 如何设计一个线程安全的类?
成员变量加互斥锁保护,接口考虑原子操作,避免死锁,返回副本而非内部引用。

77. 如何调用C语言的库?
使用extern"C"包围C库头文件,防止C++名字修饰。

78. 指针的长度
取决于平台,32位4字节,64位8字节。

79. 指针和引用的区别是什么?形参中的引用和指针?
指针可空、可重新指向,需要解引用;引用不可空、不可重新绑定,使用时像原变量。传引用避免拷贝,可直接修改实参;传指针也能修改,但需要检查空指针。

五、C++11及现代特性

80. 闭包
lambda表达式创建的匿名函数对象,可以捕获外部变量。

81. 匿名函数
没有名字的函数对象,语法:捕获列表 -> 返回类型 { 函数体 }。

82. 哈希表底层实现
数组+链表/红黑树,通过哈希函数映射到桶,冲突用链表或树解决。

83. 状态同步与帧同步
状态同步:服务器下发对象状态,客户端渲染;帧同步:服务器下发操作指令,各客户端独立计算保证结果一致。

84. 如何处理帧同步中的不同客户端的不同步的问题?
浮点数一致性(定点数代替)、随机种子统一、逻辑帧驱动、断线重连时同步快照。

85. TCP/UDP
TCP面向连接、可靠、有序、流量控制,适合文件传输;UDP无连接、不可靠、低延迟,适合实时游戏。

86. TCP拥塞的原因
网络带宽不足、路由器缓存溢出、丢包重传导致恶性循环。

87. 网络传输中为什么需要序列化?
将内存对象转为字节流,便于网络传输和跨平台解析。

88. 异步编程的同步问题如何解决?
使用锁、原子操作、消息队列、回调、future/promise、协程等。

89. 用户在输入网址后的流程
DNS解析→TCP连接→发送HTTP请求→服务器处理→返回响应→浏览器渲染。

90. UE引擎中使用UDP是如何实现可靠传输的?
应用层实现ACK确认、超时重传、序号机制,类似TCP但可定制。

六、UE引擎相关

91. Gameplay框架
包括Actor、Pawn、Controller、PlayerState、GameMode等,构成游戏逻辑的基础架构。

92. ui框架
UMG(Unreal Motion Graphics),基于Slate,可视化编辑UI,支持蓝图和C++。

93. Uobject和actor的关系
UObject是UE最基础的类,支持GC、序列化;Actor继承自UObject,可放置在游戏世界中,有生命周期。

94. UE5项目文件中宏的作用
如UPROPERTY、UFUNCTION用于反射、序列化、编辑器集成;GENERATED_BODY生成必要的内部代码。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐