各位准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";
核心作用

  1. 移动语义:避免深拷贝,直接“窃取”资源
    vector(vector&& other) : data(other.data) { 
        other.data = nullptr; // 移交所有权
    }
    
  2. 完美转发:保持参数类型(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. 多重继承的二义性

问题:菱形继承时,派生类包含多份基类副本:

A
B
C
D

二义性场景

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++常见面试题目(第六期)》!

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐