乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • C++ 学习路径
  • 第1章 C++概述与开发环境

    • C++ 语言概述与编译模型
    • 第一个 C++ 程序与规范
    • 开发环境配置
    • 预处理指令详解
  • 第2章 基本语法与类型系统

    • 变量与基本类型
    • 类型转换
    • 枚举类型
    • 引用与指针
    • 数组与 stdarray
    • 字符串与原始字符串字面量
    • const 与 constexpr
    • nullptr 与空指针
    • 类型推导 auto 与 decltype
    • 基于范围的 for 循环
    • 值类别全面解析
    • char16_t 与 char32_t
    • static_assert 编译期断言
  • 第3章 函数与重载

    • 函数声明与定义
    • 函数重载
    • 默认参数与内联函数
    • Lambda 表达式
    • 函数对象与 stdfunction
    • 后置返回类型与 noexcept
  • 第4章 类与对象

    • 类的基本定义
    • 构造函数与析构函数
    • 拷贝控制
    • 移动构造函数与移动赋值
    • 列表初始化与类内初始化器
    • 静态成员与嵌套类
    • 友元
    • =default 与 =delete
  • 第5章 继承与多态

    • 继承基础
    • 虚函数与多态
    • 虚函数表与动态绑定原理
    • 虚析构函数
    • 抽象类与纯虚函数
    • 多重继承与虚继承
    • 继承构造函数
  • 第6章 运算符重载

    • 运算符重载基础
    • 算术与关系运算符重载
    • 赋值与移动运算符重载
    • 特殊运算符重载
  • 第7章 模板与泛型编程

    • 函数模板
    • 类模板
    • 模板特化与偏特化
    • 可变参数模板
    • 别名模板与模板模板参数
    • SFINAE 与类型萃取
    • 依赖名与 typename/template 关键字
  • 第8章 异常处理

    • 异常处理机制
    • noexcept 与异常安全
    • RAII 与异常安全实践
  • 第9章 内存管理与智能指针

    • 动态内存与内存分区
    • RAII 惯用法
    • unique_ptr
    • shared_ptr 与 weak_ptr
    • 内存管理最佳实践
  • 第10章 右值引用与移动语义

    • 右值引用与值类别深度解析
    • std::move 原理与使用
    • 完美转发与 std::forward
    • 移动语义性能对比与最佳实践
  • 第11章 STL容器

    • vector 深度剖析
    • deque 内部机制
    • list 与 forward_list
    • map 与 set 深度解析
    • unordered 容器与哈希原理
    • array 与 tuple
    • 容器适配器
    • 容器选择全景指南
  • 第12章 STL算法与迭代器

    • 迭代器体系全解
    • 非变异算法
    • 变异算法
    • 排序与二分算法
    • Lambda 与算法组合
    • std::random 随机数库
    • 自定义迭代器开发
  • 第13章 IO流与文件

    • 标准 IO 流
    • 格式化输出控制
    • 文件流操作
    • 字符串流
    • std::regex 正则表达式
  • 第14章 并发与多线程

    • thread 基础与线程管理
    • mutex 与 lock_guard
    • unique_lock 与 condition_variable
    • thread_local 线程局部存储
    • atomic 与内存序
    • future 与 async 异步编程
    • std::chrono 时间库
  • 第15章 现代C++新特性

    • 从 C++11 到 C++20 演进路线
    • C++14 关键新特性
    • C++17 关键新特性
    • C++20 核心特性速览
  • 第16章 面试考点与最佳实践

    • C++ 综合最佳实践清单
    • 高频面试题精讲
    • 多线程面试题与实战
    • 内存管理常见陷阱与排查
  • 附录

    • C++ 核心知识点
    • C++ 专业术语

高频面试题精讲

定义与作用

C++ 面试通常聚焦语言核心机制的深度理解。本章精讲六大高频考点:虚函数机制、智能指针、移动语义、STL 容器底层、const 体系和 static 用法。

核心原理

六大考点框架

完整示例

考点一:虚函数与 vtable

面试原题:"请解释虚函数表(vtable)的工作机制。"

#include <iostream>
#include <string>

class Logger {
public:
    virtual ~Logger() = default;
    virtual void log(const std::string& msg) {
        std::cout << "[LOG] " << msg << "\n";
    }
};

class FileLogger : public Logger {
public:
    void log(const std::string& msg) override {
        std::cout << "[FILE] " << msg << "\n";
    }
};

class JsonLogger : public Logger {
public:
    void log(const std::string& msg) override {
        std::cout << "[JSON] " << msg << "\n";
    }
};

int main() {
    std::cout << "=== 虚函数分派 ===\n";

    Logger* loggers[3] = {
        new Logger(),
        new FileLogger(),
        new JsonLogger(),
    };

    // 动态分派:根据实际对象类型调用
    for (auto* l : loggers) {
        l->log("用户登录");  // 虚函数调用 = 指针解引用 → vtable → 函数地址
    }

    for (auto* l : loggers) delete l;
}

vtable 内存模型:

答题要点:

  • 每个含虚函数的类有一个 vtable(虚函数表),存储函数指针
  • 每个对象隐藏一个 vptr(虚表指针)指向其类的 vtable
  • 虚函数调用 = *(vptr + offset)(),即间接函数指针调用
  • 构造函数中虚函数不表现多态(vptr 尚未设置)
  • 虚函数额外开销:对象多 8 字节(64 位)vptr + 间接调用

考点二:智能指针选择与实现

面试原题:"什么时候用 unique_ptr,什么时候用 shared_ptr?"

#include <iostream>
#include <memory>

struct DatabaseConnection {
    std::string name;
    DatabaseConnection(std::string n) : name(std::move(n)) {
        std::cout << "  [连接] " << name << "\n";
    }
    ~DatabaseConnection() {
        std::cout << "  [断开] " << name << "\n";
    }
};

int main() {
    std::cout << "=== 智能指针场景 ===\n\n";

    // 场景一:独占所有权 → unique_ptr
    {
        auto conn = std::make_unique<DatabaseConnection>("DB-Master");
        // conn 独占,离开作用域自动释放
    }
    std::cout << "  (DB-Master 已释放)\n\n";

    // 场景二:共享所有权 → shared_ptr
    {
        auto sharedConn = std::make_shared<DatabaseConnection>("DB-Pool");

        {
            auto copy1 = sharedConn;  // 引用计数 +1
            auto copy2 = sharedConn;  // 引用计数 +1
            std::cout << "  引用计数: " << sharedConn.use_count() << "\n";
            // copy1, copy2 离开作用域,引用计数 -2
        }

        std::cout << "  引用计数: " << sharedConn.use_count() << "\n";
        // 只有 sharedConn 还活着
    }
    std::cout << "  (DB-Pool 已释放)\n\n";

    // 场景三:避免循环引用 → weak_ptr
    struct Node {
        std::shared_ptr<Node> next;
        std::weak_ptr<Node>   prev;  // 不增加引用计数
        int id;
        Node(int i) : id(i) {}
        ~Node() { std::cout << "  释放节点 " << id << "\n"; }
    };

    {
        auto n1 = std::make_shared<Node>(1);
        auto n2 = std::make_shared<Node>(2);

        n1->next = n2;
        n2->prev = n1;  // weak_ptr 不增加计数

        // 无循环引用,正常释放
    }
    std::cout << "  两个节点均正常释放\n";
}

答题要点:

智能指针所有权拷贝使用场景
unique_ptr独占不可拷贝,可移动工厂函数、容器元素、PIMPL
shared_ptr共享引用计数共享资源、图结构
weak_ptr观察不增加计数打破循环引用、缓存

考点三:移动语义

// "什么情况下会自动移动?"
// 1. 返回局部变量(NRVO/隐式移动)
std::vector<int> createVector() {
    std::vector<int> v{1, 2, 3, 4, 5};
    return v;  // 编译器自动移动(或 NRVO 省略)
}

// 2. 返回 std::move 局部变量 → 禁用 NRVO
std::vector<int> createVectorBad() {
    std::vector<int> v{1, 2, 3};
    return std::move(v);  // ❌ 阻止 NRVO,性能更差
}

答题要点:

  • 用 std::move 表示"这个值不再需要",而非真正移动
  • 返回局部变量不要 std::move,会阻止 NRVO
  • 移动后源对象处于"有效但未指定"状态(通常可安全析构/赋值)
  • 标记 noexcept 的移动才被 vector 扩容等场景使用

考点四:STL 容器底层

面试原题:"vector 扩容机制是怎样的?"

答题要点:

  • 动态数组,连续内存,末尾 O(1) 插入
  • 扩容策略:通常是 1.5x (GCC) 或 2x (MSVC)
  • 扩容 = 分配新内存 + 移动/拷贝元素 + 释放旧内存
  • 若移动构造是 noexcept,扩容时 move;否则 copy
  • shrink_to_fit 是请求,不保证回收
// map 底层:红黑树
// - 插入/删除/查找一律 O(log n)
// - 元素始终有序(依据 key)
// - 迭代器是双向的
// - lower_bound / upper_bound 面试高频

考点五:const 体系

// const 的四种位置
const int x = 10;           // 常量
const int* p1 = &x;         // 指向常量的指针
int* const p2 = &y;         // 常量指针
const int* const p3 = &x;   // 指向常量的常量指针

// const 成员函数
class Counter {
    int value_ = 0;
    mutable int readCount_ = 0;  // 可在 const 函数中修改
public:
    int value() const {
        readCount_++;  // OK, mutable
        return value_;
    }
};

答题要点:

  • const 修饰离它最近的左侧类型(无左侧则右侧)
  • const 成员函数不能修改非 mutable 成员,this 是 const T*
  • mutable 允许在 const 函数中修改特定成员
  • const 对象只能调用 const 成员函数

考点六:static 四种语义

位置语义示例
全局变量/函数内部链接(本翻译单元可见)static int globalId;
局部变量静态存储期(首次调用初始化,程序结束析构)static int counter = 0;
类静态成员类级别共享static int instanceCount;
类静态方法无 this 指针,只能访问静态成员static int count();

易错场景

1. 虚函数不能是模板

class Base {
    template<typename T>
    virtual void f(T t);  // ❌ 编译错误!虚函数不能是模板
};

2. shared_ptr 循环引用

struct A { std::shared_ptr<B> b; };
struct B { std::shared_ptr<A> a; };
auto a = std::make_shared<A>(), b = std::make_shared<B>();
a->b = b; b->a = a;  // ❌ 循环引用,永不释放
// 解决:一方改用 weak_ptr

3. 虚析构函数缺失

class Base { ~Base() {} };       // ❌ 非虚析构
class Derived : public Base {};
Base* p = new Derived;
delete p;  // 未定义行为:只调用 ~Base(),不调用 ~Derived()
上一页
C++ 综合最佳实践清单
下一页
多线程面试题与实战