【C++上岸】C++常见面试题目(第五期)
各位准C++大佬们!面试季又来啦~ 今天带来超干货的10大高频题,附表情包防卷护体!👇
文章目录
🧩 1. 拷贝构造函数了解吗?(⭐)
作用:用同类型对象初始化新对象时自动调用,防止浅拷贝导致的双重释放问题。
特征:
- 声明格式:
ClassName(const ClassName& other) - 默认生成浅拷贝,需手动实现深拷贝(如含指针成员)
示例:
class Vector {
public:
int* data;
// 深拷贝构造函数
Vector(const Vector& other) : data(new int[10]) {
memcpy(data, other.data, 10 * sizeof(int));
}
};
💡 面试点睛:若类中有动态资源(堆内存、文件句柄),必须手动实现拷贝构造!
⚛️ 2. 说说原子操作?
定义:不可分割的指令,多线程中避免竞态条件。
C++实现:std::atomic<T> 类型(如 atomic<int> count = 0;)
特性:
- 支持
load(),store(),exchange()等原子方法 - 无需锁即可保证线程安全
适用场景:计数器、标志位等轻量级同步。
🔒 对比锁:原子操作无上下文切换开销,但仅适用于简单操作!
➡️ 3. 什么是右值引用?作用?
右值:临时对象(如函数返回值、字面量)。
语法:T&&(例:std::string&& s = "tmp";)
核心作用:
- 移动语义:避免深拷贝,直接“窃取”资源
vector(vector&& other) : data(other.data) { other.data = nullptr; // 移交所有权 } - 完美转发:保持参数类型(
std::forward<T>)
🚀 性能关键:
vector.push_back(std::move(obj))效率提升50%+!
⚖️ 4. 析构函数必须是虚函数吗?
必须为虚:当类会被继承,且可能通过基类指针删除子类对象时:
Base* obj = new Derived();
delete obj; // 若基类析构非虚,Derived析构不被调用 → 内存泄漏!
不必为虚:
- 类不会被继承(
final类) - 无多态需求(如工具类)
- 避免虚表开销(嵌入式场景)
🧬 5. 虚函数工作机制(⭐)
核心:虚函数表(vtable) + 虚指针(vptr)
- vtable:编译器为每个多态类生成,存储虚函数地址
- vptr:对象隐含指针,指向所属类的vtable
调用过程:
graph LR
A[调用 obj->func()] --> B[通过vptr找到vtable]
B --> C[从vtable获取func地址]
C --> D[执行目标函数]
💻 汇编视角:
call [eax+4](eax=vptr, 4=函数偏移量)
🕰️ 6. 虚函数表何时创建?每个对象一份?
- vtable创建时机:编译期生成(存在只读数据段)
- vptr初始化:对象构造时由构造函数隐式设置
- 对象与vtable:
- 同类型对象共享一份vtable
- 每个对象独立拥有vptr(指向共享vtable)
⚠️ 7. 析构函数为何常为虚函数?构造函数不能虚?
析构函数虚化:确保多态删除时正确调用子类析构(防泄漏)🔥
构造函数不能虚:
- 虚调用需vptr,但vptr在构造期间才初始化 → 死锁!
构造/析构中调虚函数: - 此时对象类型为当前类(非多态),调用当前类版本!
class Base {
public:
Base() { callVirtual(); } // 调用Base::callVirtual()
virtual void callVirtual() { cout << "Base"; }
};
🔀 8. 多重继承的二义性
问题:菱形继承时,派生类包含多份基类副本:
二义性场景:
class A { public: int id; };
class B : public A {};
class C : public A {};
class D : public B, public C {};
D d;
d.id = 10; // 错误!id来自B还是C?
解决方案:虚继承(class B : virtual public A;)
📊 9. vector和list异同(⭐)
| 特性 | vector | list |
|---|---|---|
| 底层结构 | 动态数组 | 双向链表 |
| 随机访问 | ✅ O ( 1 ) O(1) O(1) | ❌ O ( n ) O(n) O(n) |
| 中间插入删除 | ❌ O ( n ) O(n) O(n) | ✅ O ( 1 ) O(1) O(1) |
| 内存连续性 | ✅ | ❌ |
| 迭代器失效 | 扩容时全失效 | 仅当前元素失效 |
📌 选型口诀:随机访问用vector,频繁插删选list!
🗺️ 10. Unordered_map vs map / Unordered_set vs set
底层结构:
| 容器 | 数据结构 | 元素顺序 |
|---|---|---|
| map/set | 红黑树(RB-Tree) | 按键升序 |
| unordered_系列 | 哈希表(Hash Table) | 无序 |
核心差异:
- 时间复杂度:
- map查找: O ( log n ) O(\log n) O(logn)
- unordered_map查找:平均 O ( 1 ) O(1) O(1),最差 O ( n ) O(n) O(n)
- 内存占用:哈希表需桶数组,通常比红黑树多占30%内存
- 使用场景:
- 需有序遍历 → map/set
- 追求极速查找 → unordered_系列
🎯 面试终极Tips:
- 虚函数题必考!画vtable示意图秒杀面试官~
- 容器对比手写表格,展现系统理解!
- 右值引用和移动语义是C++11核心考点,务必吃透!
结语
恭喜你啃完这期C++面试题精华!🎉 这些知识点都是大厂面试常客。收藏本文,面试前翻一翻,上岸更轻松! 如果觉得有用,点赞支持一下,你的鼓励是我持续更新的动力!😊 也欢迎关注我,获取更多“C++上岸”系列干货。下期见!👋
💪 觉得有用?点个赞吧!下期预告:《【C++上岸】C++常见面试题目(第六期)》!
更多推荐

所有评论(0)