跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

C++ 经典面试题精选:从基础语法到设计模式

C++ 面试题涵盖基础语法、内存管理、现代特性及设计模式。内容包含 100 道高频考点,涉及面向对象、STL、智能指针、多线程及 SOLID 原则。通过实战代码示例与原理剖析,帮助开发者系统复习核心知识点,提升面试通过率。

筑梦师发布于 2026/2/12更新于 2026/7/2843 浏览

C++ 经典面试题精选

第一部分:C++ 基础语法

面向对象基础

1. 什么是面向对象编程?C++ 中如何体现?

面向对象编程(OOP)是一种通过对象组织代码的范式。在 C++ 中主要体现在封装、继承和多态上。

class Animal {
public:
    virtual void makeSound() = 0; // 纯虚函数
};

class Dog : public Animal {
public:
    void makeSound() override {
        std::cout << "Woof!" << std::endl;
    }
};

2. 类和结构的区别?

主要区别在于默认访问权限:class 默认为 private,而 struct 默认为 public。

class MyClass {
    int x; // private
};

struct MyStruct {
    int x; // public
};

3. 构造函数的作用和种类?

构造函数用于初始化对象。包括默认构造函数、参数化构造函数、拷贝构造函数以及 C++11 引入的移动构造函数。

class Example {
public:
    Example() {} // 默认构造
    Example(int x) : val(x) {} // 参数化构造
    Example(const Example& other) : val(other.val) {} // 拷贝构造
    Example(Example&& other) noexcept : val(other.val) {} // 移动构造
private:
    int val;
};

4. 析构函数的作用?什么时候调用?

析构函数用于清理对象资源。当对象生命周期结束、使用 delete 释放动态分配对象或程序正常结束时调用。

class Resource {
public:
    Resource() { data = new int[100]; }
    ~Resource() { delete[] data; } // 释放资源
private:
    int* data;
};

5. 什么是拷贝构造函数?为什么要自己实现?

拷贝构造函数用同类型对象初始化新对象。如果类包含指针成员且需要深拷贝,或者有特殊逻辑时,必须手动实现。

class String {
public:
    String(const char* str) {
        data = new char[strlen(str) + 1];
        strcpy(data, str);
    }
    // 自定义拷贝构造函数(深拷贝)
    String(const String& other) {
        data = new char[strlen(other.data) + 1];
        strcpy(data, other.data);
    }
    ~String() { delete[] data; }
private:
    char* data;
};

6. 什么是移动构造函数?有什么优势?

移动构造函数(C++11)通过'窃取'资源而非拷贝来提高性能,避免深拷贝开销,特别适用于临时对象和大对象。

class Vector {
public:
    // 移动构造函数
    Vector(Vector&& other) noexcept
        : data(other.data), size(other.size), capacity(other.capacity) {
        other.data = nullptr;
        other.size = other.capacity = 0;
    }
private:
    int* data;
    size_t size, capacity;
};

7. 初始化列表的作用和优势?

初始化列表直接初始化类成员,效率更高(避免先默认构造再赋值)。对于 const 成员、引用成员及无默认构造函数的成员是必须的。

class Person {
public:
    Person(const std::string& name, int age)
        : name_(name), age_(age) {
        // 初始化列表
        // 构造函数体
    }
private:
    std::string name_;
    int age_;
};

8. this 指针的作用?

this 指针指向当前对象,用于区分成员变量和参数,返回当前对象的引用等。

class Student {
public:
    Student& setName(const std::string& name) {
        this->name = name; // 区分成员变量
        return *this;      // 返回当前对象引用
    }
private:
    std::string name;
};

访问控制与封装

9. public、private、protected 的区别?

  • public:类内外都可访问。
  • private:只有类内和友元可访问。
  • protected:类内、派生类、友元可访问。
class Base {
public:
    int pub; // 公有成员
protected:
    int prot; // 保护成员
private:
    int priv; // 私有成员
};

class Derived : public Base {
public:
    void access() {
        pub = 1;   // OK
        prot = 2;  // OK:派生类可访问
        // priv = 3; // Error
    }
};

10. 友元函数和友元类的作用?

友元可以访问类的私有和保护成员。友元函数是非成员函数,友元类则是另一个类的所有成员函数都可访问。

class Box {
    friend void printBox(const Box& box); // 友元函数
    friend class BoxPrinter;              // 友元类
private:
    int width, height;
};

void printBox(const Box& box) {
    std::cout << box.width << "x" << box.height;
}

11. 什么是封装?为什么重要?

封装将数据和操作数据的方法绑定在一起,隐藏内部实现。这有助于数据保护、接口清晰化和易于维护。

class BankAccount {
public:
    void deposit(double amount) { balance += amount; }
    bool withdraw(double amount) {
        if (amount <= balance) {
            balance -= amount;
            return true;
        }
        return false;
    }
    double getBalance() const { return balance; }
private:
    double balance = 0.0;
};

12. const 成员函数的作用?

承诺不修改对象状态,可以被 const 对象调用,不能修改非 mutable 成员变量,提高安全性和可读性。

class Rectangle {
public:
    double getArea() const {
        return width * height; // 只读操作
    }
    void setWidth(double w) { width = w; }
private:
    double width, height;
};

13. mutable 关键字的作用?

允许在 const 成员函数中修改特定成员变量,常用于缓存、计数器等逻辑上保持 const 但需修改的场景。

class Calculator {
public:
    int getResult() const {
        cache_count++; // mutable 成员可在 const 函数中修改
        return compute();
    }
private:
    mutable int cache_count = 0;
    int compute() const { return 42; }
};

继承与多态

14. 继承的方式有哪些?区别是什么?

C++ 有三种继承方式:public(保持访问级别)、protected(基类 public/protected 变为 protected)、private(基类 public/protected 变为 private)。

class Base {
public: int pub;
protected: int prot;
private: int priv;
};

class PublicDerived : public Base {}; // pub 保持 public

class PrivateDerived : private Base {}; // pub 和 prot 都变成 private

15. 什么是虚函数?作用是什么?

虚函数实现运行时多态,允许通过基类指针调用派生类的实现。需要 virtual 关键字声明,通过虚函数表实现。

class Shape {
public:
    virtual double getArea() const = 0; // 纯虚函数
    virtual void draw() const {
        std::cout << "Drawing shape" << std::endl;
    }
};

class Circle : public Shape {
public:
    double getArea() const override {
        return 3.14 * radius * radius;
    }
    void draw() const override {
        std::cout << "Drawing circle" << std::endl;
    }
private:
    double radius;
};

16. 纯虚函数和抽象类的概念?

  • 纯虚函数:没有实现的虚函数,= 0 表示。
  • 抽象类:包含纯虚函数的类,不能实例化。
class Animal {
public:
    virtual void makeSound() = 0; // 纯虚函数
    virtual void eat() {
        std::cout << "Eating" << std::endl;
    }
};
// Animal animal; // Error:不能实例化抽象类

class Dog : public Animal {
public:
    void makeSound() override {
        std::cout << "Woof!" << std::endl;
    }
};

17. 什么是虚函数表 (vtable)?

虚函数表是实现多态的机制。每个有虚函数的类都有一个虚函数表,对象中包含指向它的指针(vptr),表中存储虚函数的地址。

// 编译器为这个类生成虚函数表
class Base {
public:
    virtual void func1() {}
    virtual void func2() {}
};
// 内存布局:[vptr][成员变量]
// vptr 指向虚函数表:[&Base::func1, &Base::func2]

18. override 关键字的作用?

明确表示重写基类虚函数。编译器会检查是否真的重写了基类函数,防止拼写错误或参数不匹配,提高可读性。

class Base {
public:
    virtual void process(int value) {}
};

class Derived : public Base {
public:
    void process(int value) override {
        // 明确表示重写
        // 如果基类没有对应的虚函数,编译器会报错
    }
};

19. final 关键字的作用?

阻止继承或重写。修饰类表示不能被继承,修饰虚函数表示不能被重写。

class FinalClass final {
public:
    virtual void method() final {
        // 不能被重写
    }
};
// class Derived : public FinalClass {} // Error:不能继承 final 类

20. 多重继承的问题和解决方案?

问题包括菱形继承导致的二义性和数据冗余。解决方案是使用虚继承或明确作用域限定。

class Animal {
public:
    void eat() {
        std::cout << "Eating" << std::endl;
    }
};

class Mammal : virtual public Animal {};
class Bird : virtual public Animal {};

class Bat : public Mammal, public Bird {
public:
    void test() {
        eat(); // OK:没有二义性
    }
};

运算符重载

21. 运算符重载的规则和限制?

不能重载的运算符包括 ., ::, sizeof, typeid, .*, ?:。必须重载为成员函数的有 =, (), [], ->。不能改变优先级和结合性。

class Complex {
public:
    // 重载为成员函数
    Complex operator+(const Complex& other) const {
        return Complex(real + other.real, imag + other.imag);
    }
    // 重载为友元函数(二元运算符推荐)
    friend Complex operator*(const Complex& c1, const Complex& c2);
private:
    double real, imag;
};

22. 前置 ++ 和后置 ++ 的区别?

前置 ++ 无参数,返回引用;后置 ++ 带 int 参数(仅用于区分),返回值。

class Counter {
public:
    // 前置 ++
    Counter& operator++() {
        ++value;
        return *this;
    }
    // 后置 ++
    Counter operator++(int) {
        Counter temp = *this;
        ++value;
        return temp;
    }
private:
    int value = 0;
};

23. 赋值运算符重载的注意事项?

检查自赋值,返回当前对象的引用,正确处理资源,考虑异常安全。

class String {
public:
    String& operator=(const String& other) {
        if (this != &other) {
            delete[] data;
            data = new char[strlen(other.data) + 1];
            strcpy(data, other.data);
        }
        return *this;
    }
private:
    char* data;
};

24. 下标运算符 [] 的重载?

通常提供 const 和非 const 两个版本,应进行边界检查,返回引用以支持修改。

class Array {
public:
    int& operator[](size_t index) {
        if (index >= size) throw std::out_of_range("Index out of range");
        return data[index];
    }
    const int& operator[](size_t index) const {
        if (index >= size) throw std::out_of_range("Index out of range");
        return data[index];
    }
private:
    int* data;
    size_t size;
};

25. 函数调用运算符 () 的重载?

使对象可以像函数一样调用,创建函数对象(functor),支持任意参数列表,常用于 STL 算法。

class Adder {
public:
    int operator()(int a, int b) const {
        return a + b;
    }
};

class Multiplier {
private:
    int factor;
public:
    Multiplier(int f) : factor(f) {}
    int operator()(int x) const {
        return x * factor;
    }
};

// 使用 Adder add; std::cout << add(3, 4) << std::endl;
// Multiplier times3(3); std::cout << times3(5) << std::endl;

第二部分:C++ 核心特性

模板编程

26. 什么是函数模板?

允许编写泛型函数,支持多种数据类型。使用 template 关键字声明,类型参数用 typename 或 class。

template<typename T>
T max(T a, T b) {
    return (a > b) ? a : b;
}

// 使用
int i = max(3, 7);     // T = int
double d = max(3.14, 2.71); // T = double

27. 什么是类模板?

定义泛型类,支持多种数据类型。成员函数在类外定义时需要模板声明,支持非类型模板参数和特化。

template<typename T>
class Stack {
private:
    std::vector<T> elements;
public:
    void push(const T& elem) {
        elements.push_back(elem);
    }
    T pop() {
        if (elements.empty()) {
            throw std::out_of_range("Stack<>::pop(): empty stack");
        }
        T elem = elements.back();
        elements.pop_back();
        return elem;
    }
};

// 使用
Stack<int> intStack;
Stack<std::string> stringStack;

28. 模板特化的概念和用法?

为特定类型提供定制实现。分为完全特化(所有参数指定)和部分特化(部分参数指定,仅类模板)。

// 通用模板
template<typename T>
class Calculator {
public:
    T add(T a, T b) { return a + b; }
};

// 完全特化
template<>
class Calculator<const char*> {
public:
    const char* add(const char* a, const char* b) {
        char* result = new char[strlen(a) + strlen(b) + 1];
        strcpy(result, a);
        strcat(result, b);
        return result;
    }
};

// 部分特化(仅类模板)
template<typename T>
class Calculator<T*> {
public:
    T add(T* a, T* b) { return *a + *b; }
};

29. 模板参数的类型?

包括类型参数(typename T)、非类型参数(int size, bool flag)和模板模板参数(template class Container)。

template<typename T, int SIZE, bool DEBUG = false>
class Buffer {
private:
    T data[SIZE];
public:
    void set(int index, const T& value) {
        if (DEBUG) std::cout << "Setting index " << index << std::endl;
        data[index] = value;
    }
};

// 模板模板参数
template<typename T, template<typename, typename> class Container>
class Adapter {
private:
    Container<T, std::allocator<T>> container;
public:
    void add(const T& item) {
        container.push_back(item);
    }
};

30. SFINAE 是什么?

替换失败不是错误(Substitution Failure Is Not An Error)。模板参数替换失败时不会编译错误,而是寻找其他重载。常用于模板元编程和类型萃取。

template<typename T>
typename T::value_type test(typename T::iterator*);

template<typename>
int test(...);

template<typename T>
auto hasIterator(T t) -> decltype(test<T>(nullptr)) {
    return true; // 有 iterator
}

template<typename T>
int hasIterator(...) {
    return false; // 没有 iterator
}

31. 模板实例化的过程?

  1. 编译期遇到模板使用时生成具体代码。
  2. 两阶段查找:模板定义时和实例化时。
  3. 隐式实例化:使用时自动生成。
  4. 显式实例化:明确指定类型。
// 模板定义
template<typename T>
T square(T x) {
    return x * x;
}

// 隐式实例化
int result1 = square(5);       // 实例化 square<int>
double result2 = square(3.14); // 实例化 square<double>

// 显式实例化
template int square<int>(int);

32. 模板的优缺点?

优点:代码复用、类型安全、性能与手写代码相同。缺点:编译时间长、代码膨胀、调试困难、老旧编译器支持有限。

STL 容器

33. vector 的特点和适用场景?

动态数组,连续内存,随机访问,自动扩容。访问 O(1),插入删除 O(n)。适用于频繁随机访问、尾部插入。

std::vector<int> vec;
vec.push_back(1);      // 尾部插入
vec[0] = 10;           // 随机访问
vec.size();            // 元素个数
vec.capacity();        // 容量
vec.reserve(100);      // 预分配容量

34. list 的特点和适用场景?

双向链表,非连续内存,双向遍历,任意位置插入删除。访问 O(n),插入删除 O(1)。适用于频繁插入删除、不需要随机访问。

std::list<int> lst;
lst.push_front(1);     // 头部插入
lst.push_back(2);      // 尾部插入
auto it = lst.begin();
lst.insert(it, 3);     // 任意位置插入
lst.erase(it);         // 删除元素

35. map 和 unordered_map 的区别?

特性mapunordered_map
底层结构红黑树哈希表
有序性有序无序
查找复杂度O(log n)O(1) 平均
插入复杂度O(log n)O(1) 平均
内存占用较小较大
// map - 有序
std::map<std::string, int> ordered_map;
ordered_map["apple"] = 1;

// unordered_map - 无序但更快
std::unordered_map<std::string, int> unordered_map;
unordered_map["apple"] = 1;

36. set 和 multiset 的区别?

  • set:元素唯一、自动排序。
  • multiset:元素可重复、自动排序。
std::set<int> s;
s.insert(1);
s.insert(1); // 重复插入失败
// s = {1}

std::multiset<int> ms;
ms.insert(1);
ms.insert(1); // 重复插入成功
// ms = {1, 1}

37. deque 的特点?

双端队列,两端插入删除高效,非严格连续内存。两端操作 O(1),中间操作 O(n)。适用于需要在两端频繁操作。

std::deque<int> dq;
dq.push_front(1); // 头部插入
dq.push_back(2);  // 尾部插入
dq.pop_front();   // 头部删除
dq.pop_back();    // 尾部删除

38. 容器的选择策略?

  • vector:需要随机访问、尾部操作。
  • list:频繁中间插入删除。
  • deque:两端频繁操作。
  • map:需要键值对、有序。
  • unordered_map:需要键值对、无序但快速。
  • set:唯一元素、有序。
  • priority_queue:需要优先级队列。

39. 容器的 emplace 系列函数?

直接构造元素,避免临时对象。包括 emplace(指定位置)、emplace_back(尾部)、emplace_front(头部)。

std::vector<std::pair<int, std::string>> vec;
// 传统方式:构造临时对象
vec.push_back(std::make_pair(1, "hello"));
// emplace 方式:直接构造
vec.emplace_back(1, "hello"); // 更高效

40. 容器的空间配置器?

管理内存分配。默认 allocator 使用 new/delete,可自定义特殊需求或内存池以提高效率。

template<typename T>
class MyAllocator {
public:
    using value_type = T;
    T* allocate(size_t n) {
        return static_cast<T*>(::operator new(n * sizeof(T)));
    }
    void deallocate(T* p, size_t) {
        ::operator delete(p);
    }
};

// 使用自定义分配器
std::vector<int, MyAllocator<int>> vec;

STL 算法

41. sort 算法的使用和注意事项?

快速排序实现,平均 O(n log n),最坏 O(n²),不稳定排序。可提供自定义比较函数。

std::vector<int> vec = {3, 1, 4, 1, 5};

// 默认升序
std::sort(vec.begin(), vec.end());

// 降序
std::sort(vec.begin(), vec.end(), std::greater<int>());

// 自定义比较
std::sort(vec.begin(), vec.end(), [](int a, int b) {
    return a % 10 < b % 10; // 按个位数排序
});

42. find 和 binary_find 的区别?

  • find:线性搜索,O(n),适用于未排序序列。
  • binary_search:二分搜索,O(log n),需要有序序列。
std::vector<int> vec = {1, 3, 5, 7, 9};

// find - 线性搜索
auto it1 = std::find(vec.begin(), vec.end(), 5);

// binary_search - 二分搜索(需要先排序)
bool found = std::binary_search(vec.begin(), vec.end(), 5);

// lower_bound/upper_bound - 找范围
auto lower = std::lower_bound(vec.begin(), vec.end(), 5);
auto upper = std::upper_bound(vec.begin(), vec.end(), 5);

43. for_each 和范围 for 循环的区别?

  • for_each:算法函数,可配合函数对象。
  • 范围 for:语言特性,更简洁。
std::vector<int> vec = {1, 2, 3, 4, 5};

// for_each
std::for_each(vec.begin(), vec.end(), [](int& x) {
    x *= 2;
});

// 范围 for 循环
for (int& x : vec) {
    x *= 2;
}

44. transform 算法的使用?

对序列进行变换。一元变换对每个元素应用函数,二元变换对两个序列对应元素应用函数。

std::vector<int> src = {1, 2, 3, 4, 5};
std::vector<int> dest(src.size());

// 一元变换
std::transform(src.begin(), src.end(), dest.begin(), [](int x) {
    return x * x;
});

// 二元变换
std::vector<int> src2 = {5, 4, 3, 2, 1};
std::vector<int> dest2(src.size());
std::transform(src.begin(), src.end(), src2.begin(), dest2.begin(), [](int a, int b) {
    return a + b;
});

45. remove 和 erase 的区别?

  • remove:将不需要的元素移到末尾,返回新逻辑终点。
  • erase:真正删除元素。
std::vector<int> vec = {1, 2, 3, 4, 5, 3, 6};

// remove-erase 惯用法
auto new_end = std::remove(vec.begin(), vec.end(), 3); // 移动 3 到末尾
vec.erase(new_end, vec.end());                          // 真正删除

// 一行完成
vec.erase(std::remove(vec.begin(), vec.end(), 3), vec.end());

智能指针

46. unique_ptr 的特点和使用?

独占所有权的智能指针。不能复制,只能移动。自动释放,轻量级,开销接近原始指针。

std::unique_ptr<int> ptr1 = std::make_unique<int>(42);
// std::unique_ptr<int> ptr2 = ptr1; // Error:不能复制
std::unique_ptr<int> ptr2 = std::move(ptr1); // OK:移动

// 自定义删除器
std::unique_ptr<FILE, decltype(&fclose)> file(fopen("test.txt", "r"), fclose);

47. shared_ptr 的特点和使用?

共享所有权的智能指针。引用计数,多个指针共享对象。引用计数操作原子线程安全。注意循环引用可能导致泄漏。

std::shared_ptr<int> ptr1 = std::make_shared<int>(42);
std::shared_ptr<int> ptr2 = ptr1; // 引用计数 +1
std::cout << ptr1.use_count() << std::endl; // 输出 2

ptr2.reset(); // 引用计数 -1
std::cout << ptr1.use_count() << std::endl; // 输出 1

48. weak_ptr 的作用?

解决 shared_ptr 的循环引用问题。弱引用不影响引用计数,作为观察者观察 shared_ptr 管理的对象,通过 lock() 获取 shared_ptr。

class Node {
public:
    std::shared_ptr<Node> next;
    std::weak_ptr<Node> prev; // 使用 weak_ptr 避免循环引用
};

std::shared_ptr<Node> node1 = std::make_shared<Node>();
std::shared_ptr<Node> node2 = std::make_shared<Node>();
node1->next = node2;
node2->prev = node1; // weak_ptr 不增加引用计数

49. make_shared 和 make_unique 的优势?

异常安全,避免内存泄漏。性能更好,一次内存分配。代码简洁易读。

// 传统方式
std::shared_ptr<int> ptr(new int(42)); // 两次分配:对象 + 控制块

// make_shared 方式
auto ptr = std::make_shared<int>(42); // 一次分配:对象 + 控制块一起

50. 智能指针的选择策略?

  • unique_ptr:独占所有权,最轻量。
  • shared_ptr:需要共享所有权。
  • weak_ptr:解决循环引用,观察者模式。
  • 原始指针:不拥有所有权,仅观察。
// 选择指南
class Owner {
    std::unique_ptr<Resource> resource; // 独占资源
};

class Observer {
    std::weak_ptr<Subject> subject; // 观察主题
};

class Collaborator {
    std::shared_ptr<Data> data; // 协作数据
};

第三部分:内存管理与性能

内存管理

51. new 和 malloc 的区别?

特性newmalloc
类型安全安全不安全
构造函数调用不调用
析构函数delete 调用free 不调用
大小计算自动手动
失败处理抛出异常返回 NULL
重载可重载不可重载
// new - 类型安全,调用构造函数
MyClass* obj1 = new MyClass();

// malloc - 不安全,不调用构造函数
MyClass* obj2 = (MyClass*)malloc(sizeof(MyClass));

// 对应的释放
delete obj1; // 调用析构函数
free(obj2);  // 不调用析构函数

52. delete 和 free 的区别?

  • delete:调用析构函数,释放 new 分配的内存。
  • free:不调用析构函数,释放 malloc 分配的内存。
  • delete[]:调用数组析构函数。
  • 混用:new 配 delete,malloc 配 free。
// 正确配对
int* p1 = new int;
delete p1;
int* p2 = new int[10];
delete[] p2;
int* p3 = (int*)malloc(sizeof(int));
free(p3);

// 错误配对 - 未定义行为
int* p4 = new int;
free(p4); // 错误

53. 对象的内存布局?

包含虚函数表指针(有虚函数时)、成员变量(按声明顺序)、内存对齐填充、基类成员在前。

class Base {
public:
    virtual void func() {}
    int a;
    char b;
};

class Derived : public Base {
public:
    void func() override {}
    int c;
};

// Derived 内存布局:
// [vptr][a][padding][b][padding][c]

54. 内存对齐的概念和作用?

数据存储在特定地址边界,提高 CPU 访问效率。规则是按成员最大对齐值对齐,可使用 alignas 控制。

struct Example {
    char a; // 1 字节
    // 3 字节填充
    int b;  // 4 字节对齐
    char c; // 1 字节
    // 3 字节填充
}; // 总大小 12 字节

// 控制对齐
struct alignas(16) Aligned {
    int data[4];
}; // 强制 16 字节对齐

55. RAII 是什么?

资源获取即初始化(Resource Acquisition Is Initialization)。构造函数获取资源,析构函数释放资源,保证异常安全。智能指针是其典型应用。

class FileHandler {
public:
    FileHandler(const char* filename) {
        file = fopen(filename, "r");
        if (!file) throw std::runtime_error("Cannot open file");
    }
    ~FileHandler() {
        if (file) fclose(file); // 自动释放
    }
    FILE* get() { return file; }
private:
    FILE* file;
};

// 使用
{
    FileHandler fh("test.txt"); // 获取资源
    // 使用文件...
} // 自动释放资源

56. 对象的生命周期?

阶段包括分配、初始化、使用、销毁、释放。不同存储期的对象(全局、静态、局部、动态)生命周期不同。

class Lifecycle {
public:
    Lifecycle() { std::cout << "构造" << std::endl; }
    ~Lifecycle() { std::cout << "析构" << std::endl; }
};

// 不同存储期的对象
Lifecycle global_obj; // 静态存储期,程序结束时销毁

void func() {
    static Lifecycle static_obj; // 静态存储期,程序结束时销毁
    Lifecycle local_obj;         // 自动存储期,函数结束时销毁
    auto* dynamic_obj = new Lifecycle(); // 动态存储期,delete 时销毁
    delete dynamic_obj;
}

57. 内存泄漏的检测和预防?

检测工具:Valgrind、AddressSanitizer。预防策略:RAII、智能指针、代码审查。

// 使用智能指针预防泄漏
class ResourceManager {
public:
    void addResource(std::shared_ptr<Resource> resource) {
        resources.push_back(resource);
    }
private:
    std::vector<std::shared_ptr<Resource>> resources;
};

58. 自定义内存管理?

场景包括性能优化(减少分配开销)、特殊需求(固定大小块、内存池)、调试目的(跟踪内存使用)。

class MemoryPool {
private:
    struct Block {
        Block* next;
    };
    Block* freeList = nullptr;
    size_t blockSize;
    std::vector<void*> chunks;

public:
    MemoryPool(size_t size) : blockSize(size) {}

    void* allocate() {
        if (!freeList) {
            char* chunk = new char[blockSize * 100];
            chunks.push_back(chunk);
            for (int i = 0; i < 100; ++i) {
                Block* block = reinterpret_cast<Block*>(chunk + i * blockSize);
                block->next = freeList;
                freeList = block;
            }
        }
        Block* result = freeList;
        freeList = freeList->next;
        return result;
    }

    void deallocate(void* ptr) {
        Block* block = static_cast<Block*>(ptr);
        block->next = freeList;
        freeList = block;
    }
};

异常处理

59. C++ 异常处理机制?

三要素:try(可能抛出异常的代码块)、catch(捕获并处理异常)、throw(抛出异常)。

try {
    if (error) {
        throw std::runtime_error("Something went wrong");
    }
} catch (const std::runtime_error& e) {
    std::cout << "捕获异常:" << e.what() << std::endl;
} catch (...) {
    std::cout << "捕获未知异常" << std::endl;
}

60. 异常安全的级别?

  • 基本保证:无资源泄漏,对象状态有效。
  • 强保证:操作成功或回滚到原状态。
  • 不抛异常保证:noexcept,绝不抛出异常。
// 基本保证
void basicGuarantee() {
    auto* ptr = new int[100];
    try {
        process(ptr);
    } catch (...) {
        delete[] ptr;
        throw;
    }
    delete[] ptr;
}

// 强保证
void strongGuarantee(std::vector<int>& vec) {
    std::vector<int> backup = vec;
    try {
        modify(vec);
    } catch (...) {
        vec = backup;
        throw;
    }
}

// 不抛异常保证
void noThrowGuarantee() noexcept {
    // 绝不抛出异常的代码
}

61. noexcept 的作用?

指定函数不抛出异常。优化性能,抛出异常时直接 terminate。移动操作通常标记 noexcept。

// noexcept 函数
void safeFunction() noexcept {
    // 如果抛出异常,程序会调用 terminate
}

// 条件 noexcept
template<typename T>
void moveIfNoexcept(T& src, T& dest) noexcept(noexcept(T(move(src)))) {
    dest = std::move(src);
}

// 移动构造函数通常标记 noexcept
class MyClass {
public:
    MyClass(MyClass&& other) noexcept
        : data(std::move(other.data)) {}
private:
    std::vector<int> data;
};

62. 异常和错误码的比较?

特性异常错误码
性能较高开销低开销
可读性清晰分离混合逻辑
强制性强制处理可忽略
信息量丰富有限
适用场景异常情况预期错误
// 异常方式
int divide(int a, int b) {
    if (b == 0) {
        throw std::invalid_argument("Division by zero");
    }
    return a / b;
}

// 错误码方式
enum ErrorCode { SUCCESS, DIVISION_BY_ZERO };
ErrorCode divide(int a, int b, int& result) {
    if (b == 0) {
        return DIVISION_BY_ZERO;
    }
    result = a / b;
    return SUCCESS;
}

63. RAII 在异常处理中的作用?

确保异常安全。自动清理,资源管理(智能指针、文件句柄等),异常传播时资源正确释放。

class ExceptionSafe {
public:
    ExceptionSafe() {
        resource1 = acquireResource1();
        resource2 = acquireResource2();
        // 可能抛出异常
        // 如果 resource2 获取失败,resource1 会自动释放
    }
    ~ExceptionSafe() {
        releaseResource2(resource2);
        releaseResource1(resource1);
    }
private:
    Resource* resource1;
    Resource* resource2;
};

性能优化

64. 移动语义的概念和优势?

转移资源而非拷贝。避免深拷贝,提高大对象性能。右值引用绑定到临时对象。

class String {
public:
    // 拷贝构造 - 深拷贝
    String(const String& other) {
        data = new char[strlen(other.data) + 1];
        strcpy(data, other.data);
    }
    // 移动构造 - 转移资源
    String(String&& other) noexcept
        : data(other.data) {
        other.data = nullptr; // 置空原对象
    }
private:
    char* data;
};

// 使用
String s1 = "Hello";
String s2 = s1;          // 拷贝构造
String s3 = std::move(s1); // 移动构造
String s4 = String("World"); // 移动构造(临时对象)

65. 完美转发的概念?

保持参数的值类别。转发引用 template T&&,forward 函数保持左值/右值特性,通用引用可绑定左值和右值。

template<typename T>
void wrapper(T&& arg) {
    func(std::forward<T>(arg));
}

void func(int& x) { std::cout << "左值引用" << std::endl; }
void func(int&& x) { std::cout << "右值引用" << std::endl; }

int a = 10;
wrapper(a);      // 转发为左值引用
wrapper(10);     // 转发为右值引用

66. 返回值优化 (RVO)?

编译器优化,避免不必要的拷贝。NRVO 命名返回值优化。条件通常是返回局部对象。

// RVO - 编译器可能优化掉拷贝
String createString() {
    String result("Hello");
    return result; // 可能直接构造在调用者空间
}

// 更明确的写法
String createString() {
    return String("Hello"); // 更容易被优化
}

// 使用
String s = createString(); // 可能没有拷贝操作

67. 编译期优化的技巧?

constexpr 编译期计算,const 常量传播,inline 内联函数,模板元编程编译期计算。

// constexpr - 编译期计算
constexpr int factorial(int n) {
    return n <= 1 ? 1 : n * factorial(n - 1);
}

constexpr int result = factorial(5); // 编译期计算

// 模板元编程
template<int N>
struct Factorial {
    static const int value = N * Factorial<N - 1>::value;
};

template<>
struct Factorial<0> {
    static const int value = 1;
};

constexpr int fact5 = Factorial<5>::value; // 编译期计算

68. 缓存友好的编程?

遵循局部性原理(时间和空间局部性),数据结构采用连续内存访问,循环优化提高缓存命中率。

// 缓存不友好 - 跳跃访问
void badAccess(int matrix[1000][1000]) {
    for (int j = 0; j < 1000; ++j) {
        for (int i = 0; i < 1000; ++i) {
            matrix[i][j]++; // 列优先访问
        }
    }
}

// 缓存友好 - 连续访问
void goodAccess(int matrix[1000][1000]) {
    for (int i = 0; i < 1000; ++i) {
        for (int j = 0; j < 1000; ++j) {
            matrix[i][j]++; // 行优先访问
        }
    }
}

69. 预分配和容量管理?

reserve 预分配容量,resize 改变大小并初始化,shrink_to_fit 释放多余容量。避免重复分配。

std::vector<int> vec;
vec.reserve(1000); // 预分配 1000 个元素的空间

for (int i = 0; i < 1000; ++i) {
    vec.push_back(i); // 不会重新分配
}

vec.resize(2000);    // 扩展到 2000,新元素初始化为 0
vec.shrink_to_fit(); // 释放未使用的容量

70. 性能分析工具?

常用工具:gprof、perf、Valgrind、Intel VTune。

# 编译时添加调试信息
g++ -g -pg program.cpp -o program
# 运行程序生成 gmon.out
./program
# 分析性能数据
gprof program gmon.out > analysis.txt
# 使用 perf 分析
perf record ./program
perf report

第四部分:高级特性

多线程编程

71. C++11 线程的创建和管理?

支持 std::thread,join() 等待结束,detach() 分离,hardware_concurrency() 获取硬件并发数。

#include <thread>
#include <iostream>

void workerFunction(int id) {
    std::cout << "Worker " << id << " is running" << std::endl;
}

int main() {
    std::thread t1(workerFunction, 1);
    std::thread t2(workerFunction, 2);

    t1.join();
    t2.join();

    unsigned int cores = std::thread::hardware_concurrency();
    std::cout << "CPU cores: " << cores << std::endl;
    return 0;
}

72. 互斥锁的使用?

保护共享资源。std::mutex 基本锁,std::lock_guard RAII 管理,std::unique_lock 灵活管理,std::recursive_mutex 可重入锁。

#include <mutex>
#include <thread>
#include <vector>

class Counter {
private:
    int value = 0;
    std::mutex mtx;

public:
    void increment() {
        std::lock_guard<std::mutex> lock(mtx); // 自动加锁解锁
        ++value;
    }

    int getValue() {
        std::unique_lock<std::mutex> lock(mtx); // 手动控制
        int result = value;
        lock.unlock(); // 提前解锁
        return result;
    }
};

void worker(Counter& counter) {
    for (int i = 0; i < 1000; ++i) {
        counter.increment();
    }
}

int main() {
    Counter counter;
    std::vector<std::thread> threads;
    for (int i = 0; i < 10; ++i) {
        threads.emplace_back(worker, std::ref(counter));
    }
    for (auto& t : threads) {
        t.join();
    }
    std::cout << "Final value: " << counter.getValue() << std::endl;
    return 0;
}

73. 条件变量的使用?

实现线程同步。std::condition_variable,wait() 等待条件满足,notify_one() 唤醒一个,notify_all() 唤醒所有。

#include <condition_variable>
#include <queue>
#include <thread>

template<typename T>
class ThreadSafeQueue {
private:
    std::queue<T> queue;
    std::mutex mtx;
    std::condition_variable cv;
    bool done = false;

public:
    void push(const T& item) {
        {
            std::lock_guard<std::mutex> lock(mtx);
            queue.push(item);
        }
        cv.notify_one(); // 通知一个等待的线程
    }

    bool pop(T& item) {
        std::unique_lock<std::mutex> lock(mtx);
        cv.wait(lock, [this] { return !queue.empty() || done; });
        if (queue.empty() && done) {
            return false;
        }
        item = queue.front();
        queue.pop();
        return true;
    }

    void setDone() {
        {
            std::lock_guard<std::mutex> lock(mtx);
            done = true;
        }
        cv.notify_all(); // 通知所有等待的线程
    }
};

74. 原子操作的使用?

无锁编程。std::atomic,memory_order 内存序,CAS 比较并交换。

#include <atomic>
#include <thread>
#include <vector>

class AtomicCounter {
private:
    std::atomic<int> value{0};

public:
    void increment() {
        value.fetch_add(1, std::memory_order_relaxed);
    }

    int getValue() const {
        return value.load(std::memory_order_acquire);
    }

    bool compareAndSwap(int expected, int desired) {
        return value.compare_exchange_weak(expected, desired);
    }
};

// 无锁栈节点
template<typename T>
struct LockFreeNode {
    T data;
    std::atomic<LockFreeNode*> next;
};

template<typename T>
class LockFreeStack {
private:
    std::atomic<LockFreeNode<T>*> head{nullptr};

public:
    void push(const T& item) {
        LockFreeNode<T>* newNode = new LockFreeNode<T>{item, head.load()};
        while (!head.compare_exchange_weak(newNode->next, newNode)) {
            // 重试
        }
    }
};

75. 线程安全的单例模式?

Meyers 单例(C++11 保证线程安全),双重检查锁定,std::call_once。

// Meyers 单例 - C++11 线程安全
class Singleton {
public:
    static Singleton& getInstance() {
        static Singleton instance; // C++11 保证线程安全
        return instance;
    }

    void doSomething() {
        std::cout << "Doing something" << std::endl;
    }

private:
    Singleton() = default;
    ~Singleton() = default;
    Singleton(const Singleton&) = delete;
    Singleton& operator=(const Singleton&) = delete;
};

// 使用 std::call_once
class CallOnceSingleton {
private:
    static std::once_flag flag;
    static CallOnceSingleton* instance;
    CallOnceSingleton() = default;

public:
    static CallOnceSingleton& getInstance() {
        std::call_once(flag, []() {
            instance = new CallOnceSingleton();
        });
        return *instance;
    }
};

std::once_flag CallOnceSingleton::flag;
CallOnceSingleton* CallOnceSingleton::instance = nullptr;

76. future 和 promise 的使用?

异步编程。std::future 获取结果,std::promise 设置结果,std::async 异步执行,std::packaged_task 包装可调用对象。

#include <future>
#include <iostream>
#include <chrono>

// 使用 std::async
int asyncFunction() {
    std::this_thread::sleep_for(std::chrono::seconds(2));
    return 42;
}

void asyncExample() {
    std::future<int> future = std::async(std::launch::async, asyncFunction);
    std::cout << "Doing other work..." << std::endl;
    int result = future.get();
    std::cout << "Result: " << result << std::endl;
}

// 使用 promise
void promiseExample() {
    std::promise<int> promise;
    std::future<int> future = promise.get_future();
    std::thread producer([&promise]() {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        promise.set_value(100);
    });
    std::thread consumer([&future]() {
        int value = future.get();
        std::cout << "Received: " << value << std::endl;
    });
    producer.join();
    consumer.join();
}

// 使用 packaged_task
void packagedTaskExample() {
    std::packaged_task<int()> task([]() { return 123; });
    std::future<int> future = task.get_future();
    std::thread t(std::move(task));
    t.detach();
    int result = future.get();
    std::cout << "Packaged task result: " << result << std::endl;
}

77. 线程池的实现?

管理线程资源。固定数量线程,任务队列缓存待执行任务,工作线程从队列取任务执行。

#include <vector>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <future>

class ThreadPool {
private:
    std::vector<std::thread> workers;
    std::queue<std::function<void()>> tasks;
    std::mutex queue_mutex;
    std::condition_variable condition;
    bool stop = false;

public:
    ThreadPool(size_t threads) {
        for (size_t i = 0; i < threads; ++i) {
            workers.emplace_back([this] {
                while (true) {
                    std::function<void()> task;
                    {
                        std::unique_lock<std::mutex> lock(queue_mutex);
                        condition.wait(lock, [this] { return stop || !tasks.empty(); });
                        if (stop && tasks.empty()) {
                            return;
                        }
                        task = std::move(tasks.front());
                        tasks.pop();
                    }
                    task();
                }
            });
        }
    }

    template<typename F, typename... Args>
    auto enqueue(F&& f, Args&&... args)
        -> std::future<typename std::result_of<F(Args...)>::type> {
        using return_type = typename std::result_of<F(Args...)>::type;
        auto task = std::make_shared<std::packaged_task<return_type()>>(
            std::bind(std::forward<F>(f), std::forward<Args>(args)...));
        std::future<return_type> result = task->get_future();
        {
            std::unique_lock<std::mutex> lock(queue_mutex);
            if (stop) {
                throw std::runtime_error("enqueue on stopped ThreadPool");
            }
            tasks.emplace([task] { (*task)(); });
        }
        condition.notify_one();
        return result;
    }

    ~ThreadPool() {
        {
            std::unique_lock<std::mutex> lock(queue_mutex);
            stop = true;
        }
        condition.notify_all();
        for (std::thread& worker : workers) {
            worker.join();
        }
    }
};

// 使用示例
void threadPoolExample() {
    ThreadPool pool(4);
    std::vector<std::future<int>> results;
    for (int i = 0; i < 8; ++i) {
        results.emplace_back(pool.enqueue([i]() {
            std::this_thread::sleep_for(std::chrono::seconds(1));
            return i * i;
        }));
    }
    for (auto&& result : results) {
        std::cout << result.get() << std::endl;
    }
}

现代 C++ 特性

78. auto 关键字的使用?

自动类型推导。简化代码,减少冗长类型名,简化迭代器,C++14 支持函数返回值推导。注意可能降低可读性。

#include <vector>
#include <map>
#include <string>

void autoExample() {
    // 基本使用
    auto i = 42;          // int
    auto d = 3.14;        // double
    auto s = "hello";     // const char*

    // 容器迭代器
    std::vector<int> vec = {1, 2, 3, 4, 5};
    for (auto it = vec.begin(); it != vec.end(); ++it) {
        std::cout << *it << " ";
    }

    // 范围 for 循环
    for (auto& item : vec) {
        item *= 2; // 修改元素
    }

    // 复杂类型
    std::map<std::string, std::vector<int>> complex_map;
    auto& map_ref = complex_map; // 引用

    // C++14 函数返回值推导
    auto add = [](auto a, auto b) { return a + b; };
    auto result = add(3, 4);     // int
    auto result2 = add(3.14, 2.71); // double
}

79. Lambda 表达式的使用?

匿名函数。语法 [捕获] -> 返回类型 { 函数体 }。捕获方式包括值、引用、混合。应用于 STL 算法、回调函数。

#include <algorithm>
#include <vector>
#include <iostream>

void lambdaExample() {
    std::vector<int> numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    // 基本 lambda
    auto square = [](int x) { return x * x; };
    std::cout << "5 squared: " << square(5) << std::endl;

    // 捕获外部变量
    int factor = 2;
    auto multiply = [factor](int x) { return x * factor; };
    std::cout << "5 * 2: " << multiply(5) << std::endl;

    // 引用捕获
    int sum = 0;
    std::for_each(numbers.begin(), numbers.end(), [&sum](int x) {
        sum += x;
    });
    std::cout << "Sum: " << sum << std::endl;

    // 混合捕获
    int threshold = 5;
    int count = 0;
    std::for_each(numbers.begin(), numbers.end(), [threshold, &count](int x) {
        if (x > threshold) count++;
    });
    std::cout << "Numbers > 5: " << count << std::endl;

    // 可变 lambda
    int accumulator = 0;
    auto mutableLambda = [accumulator](int x) mutable {
        accumulator += x;
        return accumulator;
    };
    std::cout << mutableLambda(10) << std::endl; // 10
    std::cout << mutableLambda(20) << std::endl; // 30

    // 泛型 lambda (C++14)
    auto genericLambda = [](auto a, auto b) { return a + b; };
    std::cout << genericLambda(3, 4) << std::endl; // 7
    std::cout << genericLambda(3.14, 2.71) << std::endl; // 5.85
}

80. constexpr 的使用?

编译期常量。提高运行时性能。函数和变量都可以标记。限制只能使用编译期可用操作。

// constexpr 变量
constexpr int MAX_SIZE = 100;
constexpr double PI = 3.14159265359;

// constexpr 函数
constexpr int factorial(int n) {
    return n <= 1 ? 1 : n * factorial(n - 1);
}

constexpr int fact5 = factorial(5); // 编译期计算

// constexpr 类
class Point {
private:
    double x_, y_;
public:
    constexpr Point(double x, double y) : x_(x), y_(y) {}
    constexpr double x() const { return x_; }
    constexpr double y() const { return y_; }
    constexpr double distance() const { return x_ * x_ + y_ * y_; }
};

constexpr Point p(3.0, 4.0);
constexpr double dist = p.distance(); // 编译期计算

// constexpr 构造函数和成员函数
class Complex {
private:
    double real_, imag_;
public:
    constexpr Complex(double real, double imag) : real_(real), imag_(imag) {}
    constexpr Complex operator+(const Complex& other) const {
        return Complex(real_ + other.real_, imag_ + other.imag_);
    }
    constexpr double real() const { return real_; }
    constexpr double imag() const { return imag_; }
};

constexpr Complex c1(1.0, 2.0);
constexpr Complex c2(3.0, 4.0);
constexpr Complex c3 = c1 + c2; // 编译期计算

81. 范围 for 循环的使用?

简化遍历。语法 for (declaration : range) statement。适用于数组、容器、任何提供 begin/end 的类型。注意拷贝 vs 引用、const 修饰。

#include <vector>
#include <map>
#include <iostream>
#include <string>

void rangeForExample() {
    // 数组遍历
    int arr[] = {1, 2, 3, 4, 5};
    for (int x : arr) {
        std::cout << x << " ";
    }
    std::cout << std::endl;

    // vector 遍历
    std::vector<std::string> words = {"hello", "world", "c++"};
    // 只读遍历
    for (const auto& word : words) {
        std::cout << word << " ";
    }
    std::cout << std::endl;

    // 修改遍历
    for (auto& word : words) {
        word += "!";
    }

    // map 遍历
    std::map<int, std::string> number_map = {{1, "one"}, {2, "two"}, {3, "three"}};
    for (const auto& [key, value] : number_map) { // C++17 结构化绑定
        std::cout << key << ": " << value << std::endl;
    }

    // 自定义类型 - 需要提供 begin/end
class MyContainer {
private:
    std::vector<int> data_;
public:
    MyContainer(std::initializer_list<int> init) : data_(init) {}
    auto begin() { return data_.begin(); }
    auto end() { return data_.end(); }
    auto begin() const { return data_.begin(); }
    auto end() const { return data_.end(); }
};

MyContainer container = {10, 20, 30};
for (int x : container) {
    std::cout << x << " ";
}
std::cout << std::endl;
}

82. 结构化绑定的使用?

C++17 解包复合类型。语法 auto [a, b] = pair。适用于 pair、tuple、数组、结构体。简化多返回值处理。

#include <tuple>
#include <map>
#include <array>
#include <string>
#include <iostream>

void structuredBindingExample() {
    // pair 解包
    std::pair<int, std::string> p = {42, "answer"};
    auto [id, name] = p;
    std::cout << "id: " << id << ", name: " << name << std::endl;

    // tuple 解包
    std::tuple<int, double, std::string> t = {1, 3.14, "pi"};
    auto [i, d, s] = t;
    std::cout << i << ", " << d << ", " << s << std::endl;

    // 数组解包
    int arr[3] = {10, 20, 30};
    auto [a, b, c] = arr;
    std::cout << a << ", " << b << ", " << c << std::endl;

    // 结构体解包
    struct Point { double x, y; };
    Point pt = {3.0, 4.0};
    auto [x, y] = pt;
    std::cout << "Point: (" << x << ", " << y << ")" << std::endl;

    // map 遍历
    std::map<std::string, int> scores = {{"Alice", 95}, {"Bob", 87}, {"Charlie", 92}};
    for (const auto& [name, score] : scores) {
        std::cout << name << ": " << score << std::endl;
    }

    // 函数多返回值
    auto divide = [](double numerator, double denominator) -> std::pair<double, bool> {
        if (denominator == 0) {
            return {0.0, false};
        }
        return {numerator / denominator, true};
    };
    auto [result, success] = divide(10.0, 2.0);
    if (success) {
        std::cout << "Result: " << result << std::endl;
    }
}

83. std::optional 的使用?

表示可能不存在的值。替代空指针,类型安全。避免特殊值如 -1 表示无效。操作方法包括 value()、value_or()、has_value()。

#include <optional>
#include <string>
#include <iostream>
#include <vector>

// 函数可能返回值也可能不返回
std::optional<int> parseInt(const std::string& s) {
    try {
        return std::stoi(s);
    } catch (...) {
        return std::nullopt; // 表示没有值
    }
}

// 查找元素
std::optional<std::string> findUser(int id) {
    static std::map<int, std::string> users = {{1, "Alice"}, {2, "Bob"}, {3, "Charlie"}};
    auto it = users.find(id);
    if (it != users.end()) {
        return it->second;
    }
    return std::nullopt;
}

void optionalExample() {
    // 解析整数
    auto result1 = parseInt("123");
    auto result2 = parseInt("abc");
    if (result1) {
        std::cout << "Parsed: " << result1.value() << std::endl;
    }
    if (result2.has_value()) {
        std::cout << "Parsed: " << result2.value() << std::endl;
    } else {
        std::cout << "Invalid number" << std::endl;
    }

    // 使用 value_or 提供默认值
    int value = result2.value_or(0);
    std::cout << "Value: " << value << std::endl;

    // 查找用户
    auto user = findUser(2);
    std::cout << "User: " << user.value_or("Unknown") << std::endl;

    // optional 作为成员变量
    class Config {
    private:
        std::optional<std::string> database_url_;
        std::optional<int> timeout_;
    public:
        void setDatabaseUrl(const std::string& url) {
            database_url_ = url;
        }
        std::string getDatabaseUrl() const {
            return database_url_.value_or("localhost:5432");
        }
        void setTimeout(int seconds) {
            timeout_ = seconds;
        }
        int getTimeout() const {
            return timeout_.value_or(30); // 默认 30 秒
        }
    };

    Config config;
    config.setTimeout(60);
    std::cout << "Database: " << config.getDatabaseUrl() << std::endl;
    std::cout << "Timeout: " << config.getTimeout() << std::endl;
}

84. std::variant 的使用?

类型安全的联合体。编译期类型检查。访问方式包括 std::get、std::visit。应用场景包括多类型选择、解析结果。

#include <variant>
#include <string>
#include <iostream>
#include <vector>

// variant 可以存储多种类型中的一种
using Value = std::variant<int, double, std::string>;

void variantExample() {
    // 基本使用
    Value v1 = 42;
    Value v2 = 3.14;
    Value v3 = "hello";

    // 访问值
    if (std::holds_alternative<int>(v1)) {
        int int_val = std::get<int>(v1);
        std::cout << "Int value: " << int_val << std::endl;
    }

    // 使用 get_if 安全访问
    if (auto* str_ptr = std::get_if<std::string>(&v3)) {
        std::cout << "String value: " << *str_ptr << std::endl;
    }

    // 使用 visitor 处理不同类型
    auto visitor = [](auto&& arg) {
        using T = std::decay_t<decltype(arg)>;
        if constexpr (std::is_same_v<T, int>) {
            std::cout << "Int: " << arg << std::endl;
        } else if constexpr (std::is_same_v<T, double>) {
            std::cout << "Double: " << arg << std::endl;
        } else if constexpr (std::is_same_v<T, std::string>) {
            std::cout << "String: " << arg << std::endl;
        }
    };
    std::visit(visitor, v1);
    std::visit(visitor, v2);
    std::visit(visitor, v3);

    // variant 作为函数返回值
    std::variant<int, std::string> parseNumber(const std::string& s) {
        try {
            return std::stoi(s);
        } catch (...) {
            return "Invalid number: " + s;
        }
    }

    auto result = parseNumber("123");
    std::visit([](auto&& arg) {
        std::cout << "Parse result: " << arg << std::endl;
    }, result);

    // variant 容器
    std::vector<Value> values = {1, 2.5, "three", 4, 5.5};
    for (const auto& val : values) {
        std::visit(visitor, val);
    }
}

85. std::any 的使用?

类型安全的任意类型容器。类型擦除,存储任何类型。访问时需要类型检查,保存类型信息。

#include <any>
#include <string>
#include <iostream>
#include <vector>
#include <typeinfo>

void anyExample() {
    // 基本使用
    std::any a = 42;
    a = 3.14;
    a = std::string("hello");

    // 访问值
    if (a.type() == typeid(std::string)) {
        std::string str = std::any_cast<std::string>(a);
        std::cout << "String: " << str << std::endl;
    }

    // 使用 any_cast 安全访问
    try {
        int int_val = std::any_cast<int>(a); // 会抛出异常
    } catch (const std::bad_any_cast& e) {
        std::cout << "Bad cast: " << e.what() << std::endl;
    }

    // 使用指针访问避免异常
    if (auto* str_ptr = std::any_cast<std::string>(&a)) {
        std::cout << "String pointer: " << *str_ptr << std::endl;
    }

    // any 容器
    std::vector<std::any> values;
    values.push_back(42);
    values.push_back(3.14);
    values.push_back(std::string("world"));
    values.push_back(std::vector<int>{1, 2, 3});

    for (const auto& val : values) {
        if (val.type() == typeid(int)) {
            std::cout << "Int: " << std::any_cast<int>(val) << std::endl;
        } else if (val.type() == typeid(double)) {
            std::cout << "Double: " << std::any_cast<double>(val) << std::endl;
        } else if (val.type() == typeid(std::string)) {
            std::cout << "String: " << std::any_cast<std::string>(val) << std::endl;
        } else if (val.type() == typeid(std::vector<int>)) {
            auto vec = std::any_cast<std::vector<int>>(val);
            std::cout << "Vector: ";
            for (int x : vec) std::cout << x << " ";
            std::cout << std::endl;
        }
    }

    // any 作为函数参数
    void printAny(const std::any& value) {
        if (value.type() == typeid(int)) {
            std::cout << "Int: " << std::any_cast<int>(value) << std::endl;
        } else if (value.type() == typeid(std::string)) {
            std::cout << "String: " << std::any_cast<std::string>(value) << std::endl;
        } else {
            std::cout << "Unknown type: " << value.type().name() << std::endl;
        }
    }

    printAny(123);
    printAny(std::string("test"));

    // any 的实用场景:配置系统
    class Config {
    private:
        std::map<std::string, std::any> config_;
    public:
        template<typename T>
        void set(const std::string& key, const T& value) {
            config_[key] = value;
        }
        template<typename T>
        T get(const std::string& key, const T& default_value = T{}) const {
            auto it = config_.find(key);
            if (it != config_.end() && it->second.type() == typeid(T)) {
                return std::any_cast<T>(it->second);
            }
            return default_value;
        }
    };

    Config config;
    config.set("timeout", 30);
    config.set("name", std::string("MyApp"));
    config.set("version", 1.5);

    int timeout = config.get<int>("timeout", 60);
    std::string name = config.get<std::string>("name", "Unknown");
    double version = config.get<double>("version", 1.0);
    std::cout << "Config: " << timeout << ", " << name << ", " << version << std::endl;
}

第五部分:设计模式与架构

设计模式

86. 单例模式的实现?

确保类只有一个实例。饿汉式(启动时创建)、懒汉式(首次使用时创建)。C++11 保证 Meyers 单例线程安全。

// 饿汉式单例
class EagerSingleton {
private:
    static EagerSingleton instance;
    EagerSingleton() = default;

public:
    static EagerSingleton& getInstance() {
        return instance;
    }

    void doSomething() {
        std::cout << "Eager singleton working" << std::endl;
    }
};

EagerSingleton EagerSingleton::instance;

// 懒汉式单例(Meyers 单例)- C++11 线程安全
class LazySingleton {
private:
    LazySingleton() = default;
    ~LazySingleton() = default;
    LazySingleton(const LazySingleton&) = delete;
    LazySingleton& operator=(const LazySingleton&) = delete;

public:
    static LazySingleton& getInstance() {
        static LazySingleton instance; // C++11 保证线程安全
        return instance;
    }

    void doSomething() {
        std::cout << "Lazy singleton working" << std::endl;
    }
};

// 使用示例
void singletonExample() {
    LazySingleton& s1 = LazySingleton::getInstance();
    LazySingleton& s2 = LazySingleton::getInstance();
    std::cout << "Same instance: " << (&s1 == &s2) << std::endl;
    s1.doSomething();
}

87. 工厂模式的实现?

创建对象而不暴露创建逻辑。简单工厂(一个工厂类)、工厂方法(每个产品对应工厂)、抽象工厂(产品族)。

#include <memory>
#include <string>
#include <iostream>

// 产品接口
class Shape {
public:
    virtual ~Shape() = default;
    virtual void draw() const = 0;
};

// 具体产品
class Circle : public Shape {
public:
    void draw() const override {
        std::cout << "Drawing Circle" << std::endl;
    }
};

class Rectangle : public Shape {
public:
    void draw() const override {
        std::cout << "Drawing Rectangle" << std::endl;
    }
};

class Triangle : public Shape {
public:
    void draw() const override {
        std::cout << "Drawing Triangle" << std::endl;
    }
};

// 简单工厂
class SimpleShapeFactory {
public:
    enum class ShapeType { CIRCLE, RECTANGLE, TRIANGLE };
    static std::unique_ptr<Shape> createShape(ShapeType type) {
        switch (type) {
        case ShapeType::CIRCLE:
            return std::make_unique<Circle>();
        case ShapeType::RECTANGLE:
            return std::make_unique<Rectangle>();
        case ShapeType::TRIANGLE:
            return std::make_unique<Triangle>();
        default:
            return nullptr;
        }
    }
};

// 工厂方法模式
class ShapeFactory {
public:
    virtual ~ShapeFactory() = default;
    virtual std::unique_ptr<Shape> createShape() const = 0;
};

class CircleFactory : public ShapeFactory {
public:
    std::unique_ptr<Shape> createShape() const override {
        return std::make_unique<Circle>();
    }
};

class RectangleFactory : public ShapeFactory {
public:
    std::unique_ptr<Shape> createShape() const override {
        return std::make_unique<Rectangle>();
    }
};

// 使用示例
void factoryExample() {
    // 简单工厂
    auto circle = SimpleShapeFactory::createShape(SimpleShapeFactory::ShapeType::CIRCLE);
    auto rectangle = SimpleShapeFactory::createShape(SimpleShapeFactory::ShapeType::RECTANGLE);
    circle->draw();
    rectangle->draw();

    // 工厂方法
    CircleFactory circleFactory;
    RectangleFactory rectangleFactory;
    auto circle2 = circleFactory.createShape();
    auto rectangle2 = rectangleFactory.createShape();
    circle2->draw();
    rectangle2->draw();
}

88. 观察者模式的实现?

定义对象间一对多依赖。主题维护观察者列表,观察者接收通知。松耦合。

#include <vector>
#include <string>
#include <iostream>
#include <algorithm>

// 观察者接口
class Observer {
public:
    virtual ~Observer() = default;
    virtual void update(const std::string& message) = 0;
};

// 主题接口
class Subject {
public:
    virtual ~Subject() = default;
    virtual void attach(Observer* observer) = 0;
    virtual void detach(Observer* observer) = 0;
    virtual void notify(const std::string& message) = 0;
};

// 具体主题
class NewsAgency : public Subject {
private:
    std::vector<Observer*> observers;
    std::string latestNews;

public:
    void attach(Observer* observer) override {
        observers.push_back(observer);
    }

    void detach(Observer* observer) override {
        observers.erase(
            std::remove(observers.begin(), observers.end(), observer),
            observers.end());
    }

    void notify(const std::string& message) override {
        latestNews = message;
        for (Observer* observer : observers) {
            observer->update(message);
        }
    }

    void setNews(const std::string& news) {
        notify(news);
    }
};

// 具体观察者
class NewsSubscriber : public Observer {
private:
    std::string name;

public:
    NewsSubscriber(const std::string& subscriberName) : name(subscriberName) {}

    void update(const std::string& message) override {
        std::cout << name << " received news: " << message << std::endl;
    }
};

// 使用示例
void observerExample() {
    NewsAgency agency;
    NewsSubscriber alice("Alice");
    NewsSubscriber bob("Bob");
    NewsSubscriber charlie("Charlie");

    agency.attach(&alice);
    agency.attach(&bob);
    agency.attach(&charlie);

    agency.setNews("Breaking: C++20 is released!");
    agency.detach(&bob);
    agency.setNews("Update: New C++ features available!");
}

89. 策略模式的实现?

定义算法族,可互换使用。策略接口定义算法,具体策略实现算法,上下文使用策略对象。

#include <memory>
#include <vector>
#include <algorithm>
#include <iostream>

// 策略接口
class SortStrategy {
public:
    virtual ~SortStrategy() = default;
    virtual void sort(std::vector<int>& data) const = 0;
};

// 具体策略
class BubbleSort : public SortStrategy {
public:
    void sort(std::vector<int>& data) const override {
        std::cout << "Using Bubble Sort" << std::endl;
        int n = data.size();
        for (int i = 0; i < n - 1; ++i) {
            for (int j = 0; j < n - i - 1; ++j) {
                if (data[j] > data[j + 1]) {
                    std::swap(data[j], data[j + 1]);
                }
            }
        }
    }
};

class QuickSort : public SortStrategy {
public:
    void sort(std::vector<int>& data) const override {
        std::cout << "Using Quick Sort" << std::endl;
        std::sort(data.begin(), data.end());
    }
};

class InsertionSort : public SortStrategy {
public:
    void sort(std::vector<int>& data) const override {
        std::cout << "Using Insertion Sort" << std::endl;
        for (size_t i = 1; i < data.size(); ++i) {
            int key = data[i];
            int j = static_cast<int>(i) - 1;
            while (j >= 0 && data[j] > key) {
                data[j + 1] = data[j];
                j--;
            }
            data[j + 1] = key;
        }
    }
};

// 上下文
class Sorter {
private:
    std::unique_ptr<SortStrategy> strategy;

public:
    void setStrategy(std::unique_ptr<SortStrategy> newStrategy) {
        strategy = std::move(newStrategy);
    }

    void sort(std::vector<int>& data) const {
        if (strategy) {
            strategy->sort(data);
        }
    }
};

// 使用示例
void strategyExample() {
    std::vector<int> data = {64, 34, 25, 12, 22, 11, 90};
    Sorter sorter;

    // 使用冒泡排序
    sorter.setStrategy(std::make_unique<BubbleSort>());
    auto data1 = data;
    sorter.sort(data1);

    // 使用快速排序
    sorter.setStrategy(std::make_unique<QuickSort>());
    auto data2 = data;
    sorter.sort(data2);

    // 使用插入排序
    sorter.setStrategy(std::make_unique<InsertionSort>());
    auto data3 = data;
    sorter.sort(data3);
}

90. 装饰器模式的实现?

动态添加对象功能。组件接口定义基础,具体组件实现基础,装饰器添加额外功能。

#include <string>
#include <iostream>
#include <memory>

// 组件接口
class Coffee {
public:
    virtual ~Coffee() = default;
    virtual std::string getDescription() const = 0;
    virtual double cost() const = 0;
};

// 具体组件
class SimpleCoffee : public Coffee {
public:
    std::string getDescription() const override {
        return "Simple Coffee";
    }
    double cost() const override {
        return 2.0;
    }
};

// 装饰器基类
class CoffeeDecorator : public Coffee {
private:
    std::unique_ptr<Coffee> coffee;

public:
    CoffeeDecorator(std::unique_ptr<Coffee> c) : coffee(std::move(c)) {}

    std::string getDescription() const override {
        return coffee->getDescription();
    }

    double cost() const override {
        return coffee->cost();
    }

protected:
    Coffee* getCoffee() const {
        return coffee.get();
    }
};

// 具体装饰器
class MilkDecorator : public CoffeeDecorator {
public:
    MilkDecorator(std::unique_ptr<Coffee> c) : CoffeeDecorator(std::move(c)) {}
    std::string getDescription() const override {
        return getCoffee()->getDescription() + ", Milk";
    }
    double cost() const override {
        return getCoffee()->cost() + 0.5;
    }
};

class SugarDecorator : public CoffeeDecorator {
public:
    SugarDecorator(std::unique_ptr<Coffee> c) : CoffeeDecorator(std::move(c)) {}
    std::string getDescription() const override {
        return getCoffee()->getDescription() + ", Sugar";
    }
    double cost() const override {
        return getCoffee()->cost() + 0.2;
    }
};

class VanillaDecorator : public CoffeeDecorator {
public:
    VanillaDecorator(std::unique_ptr<Coffee> c) : CoffeeDecorator(std::move(c)) {}
    std::string getDescription() const override {
        return getCoffee()->getDescription() + ", Vanilla";
    }
    double cost() const override {
        return getCoffee()->cost() + 0.7;
    }
};

// 使用示例
void decoratorExample() {
    // 简单咖啡
    auto coffee = std::make_unique<SimpleCoffee>();
    std::cout << coffee->getDescription() << " $" << coffee->cost() << std::endl;

    // 加牛奶的咖啡
    auto milkCoffee = std::make_unique<MilkDecorator>(std::make_unique<SimpleCoffee>());
    std::cout << milkCoffee->getDescription() << " $" << milkCoffee->cost() << std::endl;

    // 加牛奶和糖的咖啡
    auto milkSugarCoffee = std::make_unique<SugarDecorator>(
        std::make_unique<MilkDecorator>(std::make_unique<SimpleCoffee>()));
    std::cout << milkSugarCoffee->getDescription() << " $" << milkSugarCoffee->cost() << std::endl;

    // 复杂组合
    auto complexCoffee = std::make_unique<VanillaDecorator>(
        std::make_unique<SugarDecorator>(
            std::make_unique<MilkDecorator>(std::make_unique<SimpleCoffee>())));
    std::cout << complexCoffee->getDescription() << " $" << complexCoffee->cost() << std::endl;
}

91. 适配器模式的实现?

使不兼容接口协同工作。目标接口客户端期望,适配者现有接口,适配器转换接口。

#include <string>
#include <iostream>
#include <memory>

// 目标接口
class MediaPlayer {
public:
    virtual ~MediaPlayer() = default;
    virtual void play(const std::string& audioType, const std::string& fileName) = 0;
};

// 适配者接口
class AdvancedMediaPlayer {
public:
    virtual ~AdvancedMediaPlayer() = default;
    virtual void playVlc(const std::string& fileName) = 0;
    virtual void playMp4(const std::string& fileName) = 0;
};

// 具体适配者
class VlcPlayer : public AdvancedMediaPlayer {
public:
    void playVlc(const std::string& fileName) override {
        std::cout << "Playing vlc file: " << fileName << std::endl;
    }
    void playMp4(const std::string& fileName) override {
        // 什么都不做
    }
};

class Mp4Player : public AdvancedMediaPlayer {
public:
    void playVlc(const std::string& fileName) override {
        // 什么都不做
    }
    void playMp4(const std::string& fileName) override {
        std::cout << "Playing mp4 file: " << fileName << std::endl;
    }
};

// 适配器
class MediaAdapter : public MediaPlayer {
private:
    std::unique_ptr<AdvancedMediaPlayer> advancedMusicPlayer;

public:
    MediaAdapter(const std::string& audioType) {
        if (audioType == "vlc") {
            advancedMusicPlayer = std::make_unique<VlcPlayer>();
        } else if (audioType == "mp4") {
            advancedMusicPlayer = std::make_unique<Mp4Player>();
        }
    }

    void play(const std::string& audioType, const std::string& fileName) override {
        if (audioType == "vlc") {
            advancedMusicPlayer->playVlc(fileName);
        } else if (audioType == "mp4") {
            advancedMusicPlayer->playMp4(fileName);
        }
    }
};

// 具体目标类
class AudioPlayer : public MediaPlayer {
private:
    std::unique_ptr<MediaAdapter> mediaAdapter;

public:
    void play(const std::string& audioType, const std::string& fileName) override {
        // 内置支持 mp3
        if (audioType == "mp3") {
            std::cout << "Playing mp3 file: " << fileName << std::endl;
        }
        // 使用适配器支持其他格式
        else if (audioType == "vlc" || audioType == "mp4") {
            mediaAdapter = std::make_unique<MediaAdapter>(audioType);
            mediaAdapter->play(audioType, fileName);
        } else {
            std::cout << "Invalid media. " << audioType << " format not supported" << std::endl;
        }
    }
};

// 使用示例
void adapterExample() {
    AudioPlayer player;
    player.play("mp3", "song.mp3");
    player.play("mp4", "video.mp4");
    player.play("vlc", "movie.vlc");
    player.play("avi", "video.avi");
}

92. 命令模式的实现?

将请求封装为对象。命令接口声明执行,具体命令实现,调用者调用执行,接收者执行操作。

#include <string>
#include <iostream>
#include <vector>
#include <memory>

// 命令接口
class Command {
public:
    virtual ~Command() = default;
    virtual void execute() = 0;
    virtual void undo() = 0;
};

// 接收者
class Light {
public:
    void turnOn() {
        std::cout << "Light is ON" << std::endl;
        isOn = true;
    }
    void turnOff() {
        std::cout << "Light is OFF" << std::endl;
        isOn = false;
    }
    bool getState() const { return isOn; }

private:
    bool isOn = false;
};

class Stereo {
public:
    void on() { std::cout << "Stereo is ON" << std::endl; }
    void off() { std::cout << "Stereo is OFF" << std::endl; }
    void setCd() { std::cout << "Stereo is set for CD input" << std::endl; }
    void setVolume(int volume) { std::cout << "Stereo volume set to " << volume << std::endl; }
};

// 具体命令
class LightOnCommand : public Command {
private:
    Light* light;

public:
    LightOnCommand(Light* l) : light(l) {}
    void execute() override { light->turnOn(); }
    void undo() override { light->turnOff(); }
};

class LightOffCommand : public Command {
private:
    Light* light;

public:
    LightOffCommand(Light* l) : light(l) {}
    void execute() override { light->turnOff(); }
    void undo() override { light->turnOn(); }
};

class StereoOnWithCdCommand : public Command {
private:
    Stereo* stereo;

public:
    StereoOnWithCdCommand(Stereo* s) : stereo(s) {}
    void execute() override {
        stereo->on();
        stereo->setCd();
        stereo->setVolume(11);
    }
    void undo() override { stereo->off(); }
};

// 调用者
class RemoteControl {
private:
    std::vector<std::unique_ptr<Command>> undoStack;
    std::unique_ptr<Command> currentCommand;

public:
    void setCommand(std::unique_ptr<Command> command) {
        currentCommand = std::move(command);
    }

    void buttonWasPressed() {
        if (currentCommand) {
            currentCommand->execute();
            undoStack.push_back(std::move(currentCommand));
        }
    }

    void undoButtonWasPressed() {
        if (!undoStack.empty()) {
            auto lastCommand = std::move(undoStack.back());
            undoStack.pop_back();
            lastCommand->undo();
        }
    }
};

// 使用示例
void commandExample() {
    RemoteControl remote;
    Light livingRoomLight;
    Stereo stereo;

    // 设置命令
    remote.setCommand(std::make_unique<LightOnCommand>(&livingRoomLight));
    remote.buttonWasPressed();

    remote.setCommand(std::make_unique<StereoOnWithCdCommand>(&stereo));
    remote.buttonWasPressed();

    // 撤销操作
    remote.undoButtonWasPressed();
    remote.undoButtonWasPressed();
}

93. 模板方法模式的实现?

定义算法骨架,子类实现具体步骤。抽象类定义模板方法和抽象步骤,具体类实现具体步骤。

#include <iostream>
#include <string>

// 抽象类
class DataProcessor {
public:
    // 模板方法 - 定义算法骨架
    void processData() {
        loadData();
        if (validateData()) {
            transformData();
            saveData();
        } else {
            std::cout << "Data validation failed" << std::endl;
        }
        cleanup();
    }

protected:
    // 抽象步骤 - 子类必须实现
    virtual void loadData() = 0;
    virtual void transformData() = 0;
    virtual void saveData() = 0;

    // 钩子方法 - 子类可以重写
    virtual bool validateData() { return true; }
    virtual void cleanup() { std::cout << "Default cleanup" << std::endl; }
};

// 具体实现类
class CSVProcessor : public DataProcessor {
protected:
    void loadData() override { std::cout << "Loading CSV data" << std::endl; }
    void transformData() override { std::cout << "Transforming CSV data" << std::endl; }
    void saveData() override { std::cout << "Saving CSV data" << std::endl; }
    bool validateData() override {
        std::cout << "Validating CSV format" << std::endl;
        return true;
    }
    void cleanup() override { std::cout << "CSV specific cleanup" << std::endl; }
};

class JSONProcessor : public DataProcessor {
protected:
    void loadData() override { std::cout << "Loading JSON data" << std::endl; }
    void transformData() override { std::cout << "Transforming JSON data" << std::endl; }
    void saveData() override { std::cout << "Saving JSON data" << std::endl; }
    bool validateData() override {
        std::cout << "Validating JSON structure" << std::endl;
        return false; // 模拟验证失败
    }
};

class XMLProcessor : public DataProcessor {
protected:
    void loadData() override { std::cout << "Loading XML data" << std::endl; }
    void transformData() override { std::cout << "Transforming JSON data" << std::endl; }
    void saveData() override { std::cout << "Saving XML data" << std::endl; }
    // 使用默认的 validateData 和 cleanup
};

// 使用示例
void templateMethodExample() {
    std::cout << "Processing CSV:" << std::endl;
    CSVProcessor csvProcessor;
    csvProcessor.processData();

    std::cout << "\nProcessing JSON:" << std::endl;
    JSONProcessor jsonProcessor;
    jsonProcessor.processData();

    std::cout << "\nProcessing XML:" << std::endl;
    XMLProcessor xmlProcessor;
    xmlProcessor.processData();
}

94. 状态模式的实现?

允许对象在内部状态改变时改变行为。状态接口定义行为,具体状态实现行为,上下文维护当前状态。

#include <iostream>
#include <string>
#include <memory>

// 前向声明
class Context;

// 状态接口
class State {
public:
    virtual ~State() = default;
    virtual void insertCoin(Context* context) = 0;
    virtual void ejectCoin(Context* context) = 0;
    virtual void turnCrank(Context* context) = 0;
    virtual void dispense(Context* context) = 0;
    virtual std::string getName() const = 0;
};

// 上下文
class Context {
private:
    std::unique_ptr<State> currentState;
    int count = 0;

public:
    Context(std::unique_ptr<State> initialState) : currentState(std::move(initialState)) {}

    void setState(std::unique_ptr<State> newState) {
        currentState = std::move(newState);
    }

    State* getState() const { return currentState.get(); }
    int getCount() const { return count; }
    void setCount(int c) { count = c; }

    void insertCoin() { currentState->insertCoin(this); }
    void ejectCoin() { currentState->ejectCoin(this); }
    void turnCrank() { currentState->turnCrank(this); }
    void dispense() { currentState->dispense(this); }

    void releaseBall() {
        std::cout << "A gumball comes rolling out the slot" << std::endl;
        if (count > 0) {
            count--;
        }
    }
};

// 具体状态
class NoCoinState : public State {
public:
    void insertCoin(Context* context) override;
    void ejectCoin(Context* context) override;
    void turnCrank(Context* context) override;
    void dispense(Context* context) override;
    std::string getName() const override { return "NoCoinState"; }
};

class HasCoinState : public State {
public:
    void insertCoin(Context* context) override;
    void ejectCoin(Context* context) override;
    void turnCrank(Context* context) override;
    void dispense(Context* context) override;
    std::string getName() const override { return "HasCoinState"; }
};

class SoldState : public State {
public:
    void insertCoin(Context* context) override;
    void ejectCoin(Context* context) override;
    void turnCrank(Context* context) override;
    void dispense(Context* context) override;
    std::string getName() const override { return "SoldState"; }
};

class SoldOutState : public State {
public:
    void insertCoin(Context* context) override;
    void ejectCoin(Context* context) override;
    void turnCrank(Context* context) override;
    void dispense(Context* context) override;
    std::string getName() const override { return "SoldOutState"; }
};

// 实现具体状态方法
void NoCoinState::insertCoin(Context* context) {
    std::cout << "You inserted a coin" << std::endl;
    context->setState(std::make_unique<HasCoinState>());
}
void NoCoinState::ejectCoin(Context* context) {
    std::cout << "You haven't inserted a coin" << std::endl;
}
void NoCoinState::turnCrank(Context* context) {
    std::cout << "You turned, but there's no coin" << std::endl;
}
void NoCoinState::dispense(Context* context) {
    std::cout << "You need to pay first" << std::endl;
}
void HasCoinState::insertCoin(Context* context) {
    std::cout << "You can't insert another coin" << std::endl;
}
void HasCoinState::ejectCoin(Context* context) {
    std::cout << "Coin returned" << std::endl;
    context->setState(std::make_unique<NoCoinState>());
}
void HasCoinState::turnCrank(Context* context) {
    std::cout << "You turned..." << std::endl;
    context->setState(std::make_unique<SoldState>());
}
void HasCoinState::dispense(Context* context) {
    std::cout << "No gumball dispensed" << std::endl;
}
void SoldState::insertCoin(Context* context) {
    std::cout << "Please wait, we're already giving you a gumball" << std::endl;
}
void SoldState::ejectCoin(Context* context) {
    std::cout << "Sorry, you already turned the crank" << std::endl;
}
void SoldState::turnCrank(Context* context) {
    std::cout << "Turning twice doesn't get you another gumball" << std::endl;
}
void SoldState::dispense(Context* context) {
    context->releaseBall();
    if (context->getCount() > 0) {
        context->setState(std::make_unique<NoCoinState>());
    } else {
        context->setState(std::make_unique<SoldOutState>());
    }
}
void SoldOutState::insertCoin(Context* context) {
    std::cout << "You can't insert a coin, the machine is sold out" << std::endl;
}
void SoldOutState::ejectCoin(Context* context) {
    std::cout << "You can't eject, you haven't inserted a coin yet" << std::endl;
}
void SoldOutState::turnCrank(Context* context) {
    std::cout << "You turned, but there are no gumballs" << std::endl;
}
void SoldOutState::dispense(Context* context) {
    std::cout << "No gumball dispensed" << std::endl;
}

// 使用示例
void stateExample() {
    Context gumballMachine(std::make_unique<NoCoinState>());
    gumballMachine.setCount(5);
    std::cout << "Current state: " << gumballMachine.getState()->getName() << std::endl;
    gumballMachine.insertCoin();
    std::cout << "Current state: " << gumballMachine.getState()->getName() << std::endl;
    gumballMachine.turnCrank();
    std::cout << "Current state: " << gumballMachine.getState()->getName() << std::endl;
    gumballMachine.insertCoin();
    gumballMachine.ejectCoin();
    std::cout << "Current state: " << gumballMachine.getState()->getName() << std::endl;
}

95. 代理模式的实现?

为其他对象提供代理以控制访问。主题接口定义公共接口,真实主题实现业务逻辑,代理控制访问。

#include <iostream>
#include <string>
#include <memory>

// 主题接口
class Image {
public:
    virtual ~Image() = default;
    virtual void display() = 0;
};

// 真实主题
class RealImage : public Image {
private:
    std::string fileName;
    void loadFromDisk() {
        std::cout << "Loading " << fileName << " from disk" << std::endl;
    }

public:
    RealImage(const std::string& file) : fileName(file) {
        loadFromDisk();
    }
    void display() override {
        std::cout << "Displaying " << fileName << std::endl;
    }
};

// 代理
class ProxyImage : public Image {
private:
    std::unique_ptr<RealImage> realImage;
    std::string fileName;

public:
    ProxyImage(const std::string& file) : fileName(file) {}

    void display() override {
        if (!realImage) {
            realImage = std::make_unique<RealImage>(fileName);
        }
        realImage->display();
    }
};

// 使用示例
void proxyExample() {
    std::cout << "Creating proxy images..." << std::endl;
    Image* image1 = new ProxyImage("image1.jpg");
    Image* image2 = new ProxyImage("image2.jpg");

    std::cout << "Images created, but not loaded yet" << std::endl;

    std::cout << "\nFirst display:" << std::endl;
    image1->display();

    std::cout << "\nSecond display:" << std::endl;
    image1->display();

    std::cout << "\nDisplaying second image:" << std::endl;
    image2->display();

    delete image1;
    delete image2;
}

// 保护代理示例
class InternetAccess {
public:
    virtual ~InternetAccess() = default;
    virtual void connectTo(const std::string& serverHost) = 0;
};

class RealInternetAccess : public InternetAccess {
public:
    void connectTo(const std::string& serverHost) override {
        std::cout << "Connecting to " << serverHost << std::endl;
    }
};

class ProxyInternetAccess : public InternetAccess {
private:
    std::unique_ptr<RealInternetAccess> realInternet;
    std::string username;

    bool isAccessAllowed() const {
        return username == "admin" || username == "user";
    }

public:
    ProxyInternetAccess(const std::string& user) : username(user) {}

    void connectTo(const std::string& serverHost) override {
        if (!isAccessAllowed()) {
            std::cout << "Access denied for user: " << username << std::endl;
            return;
        }
        if (!realInternet) {
            realInternet = std::make_unique<RealInternetAccess>();
        }
        realInternet->connectTo(serverHost);
    }
};

void protectionProxyExample() {
    InternetAccess* adminAccess = new ProxyInternetAccess("admin");
    InternetAccess* guestAccess = new ProxyInternetAccess("guest");
    adminAccess->connectTo("google.com");
    guestAccess->connectTo("google.com");
    delete adminAccess;
    delete guestAccess;
}

架构设计

96. SOLID 原则的解释?

SOLID 是面向对象设计的五个基本原则:单一职责、开闭、里氏替换、接口隔离、依赖倒置。

S - 单一职责原则 (SRP) 一个类应该只有一个引起变化的原因,每个类只负责一个功能。

// 违反 SRP
class User {
public:
    void saveToDatabase() { /* 数据库操作 */ }
    void validateEmail() { /* 验证逻辑 */ }
    void sendEmail() { /* 邮件发送 */ }
};

// 遵循 SRP
class UserRepository {
public:
    void save(const User& user) { /* 数据库操作 */ }
};

class EmailValidator {
public:
    bool isValid(const std::string& email) { /* 验证逻辑 */ }
};

class EmailService {
public:
    void send(const std::string& to, const std::string& message) { /* 发送邮件 */ }
};

O - 开闭原则 (OCP) 对扩展开放,对修改关闭。通过继承和组合实现扩展。

// 违反 OCP
class AreaCalculator {
public:
    double calculate(const std::string& shape, double width, double height) {
        if (shape == "rectangle") return width * height;
        if (shape == "circle") return 3.14 * width * width;
        return 0;
    }
};

// 遵循 OCP
class Shape {
public:
    virtual ~Shape() = default;
    virtual double area() const = 0;
};

class Rectangle : public Shape {
private:
    double width, height;
public:
    Rectangle(double w, double h) : width(w), height(h) {}
    double area() const override { return width * height; }
};

class Circle : public Shape {
private:
    double radius;
public:
    Circle(double r) : radius(r) {}
    double area() const override { return 3.14 * radius * radius; }
};

L - 里氏替换原则 (LSP) 子类必须能够替换其基类,子类不应破坏基类的约定。

// 违反 LSP
class Bird {
public:
    virtual void fly() {
        std::cout << "Flying" << std::endl;
    }
};

class Penguin : public Bird {
public:
    void fly() override {
        throw std::runtime_error("Penguins can't fly");
    }
};

// 遵循 LSP
class Bird {
public:
    virtual ~Bird() = default;
    virtual void makeSound() = 0;
};

class FlyingBird : public Bird {
public:
    void fly() {
        std::cout << "Flying" << std::endl;
    }
};

class Penguin : public Bird {
public:
    void makeSound() override {
        std::cout << "Squawk" << std::endl;
    }
};

I - 接口隔离原则 (ISP) 客户端不应依赖它不需要的接口,将大接口拆分为小接口。

// 违反 ISP
class Worker {
public:
    virtual void work() = 0;
    virtual void eat() = 0;
    virtual void sleep() = 0;
};

class Robot : public Worker {
public:
    void work() override { /* 工作 */ }
    void eat() override { /* 机器人不需要吃饭 */ }
    void sleep() override { /* 机器人不需要睡觉 */ }
};

// 遵循 ISP
class Workable {
public:
    virtual ~Workable() = default;
    virtual void work() = 0;
};

class Eatable {
public:
    virtual ~Eatable() = default;
    virtual void eat() = 0;
};

class Human : public Workable, public Eatable {
public:
    void work() override { /* 工作 */ }
    void eat() override { /* 吃饭 */ }
};

class Robot : public Workable {
public:
    void work() override { /* 工作 */ }
};

D - 依赖倒置原则 (DIP) 高层模块不应依赖低层模块,都应依赖抽象。抽象不应依赖细节,细节应依赖抽象。

// 违反 DIP
class LightBulb {
public:
    void turnOn() {
        std::cout << "LightBulb on" << std::endl;
    }
};

class Switch {
private:
    LightBulb bulb;
public:
    Switch() : bulb() {}
    void press() {
        bulb.turnOn();
    }
};

// 遵循 DIP
class Switchable {
public:
    virtual ~Switchable() = default;
    virtual void turnOn() = 0;
    virtual void turnOff() = 0;
};

class LightBulb : public Switchable {
public:
    void turnOn() override {
        std::cout << "LightBulb on" << std::endl;
    }
    void turnOff() override {
        std::cout << "LightBulb off" << std::endl;
    }
};

class Fan : public Switchable {
public:
    void turnOn() override {
        std::cout << "Fan on" << std::endl;
    }
    void turnOff() override {
        std::cout << "Fan off" << std::endl;
    }
};

class Switch {
private:
    Switchable& device;
public:
    Switch(Switchable& d) : device(d) {}
    void press() {
        device.turnOn();
    }
};

97. 依赖注入的实现?

将依赖关系外部注入。构造函数注入、Setter 注入、接口注入。

#include <memory>
#include <iostream>
#include <string>

// 服务接口
class ILogger {
public:
    virtual ~ILogger() = default;
    virtual void log(const std::string& message) = 0;
};

class IDatabase {
public:
    virtual ~IDatabase() = default;
    virtual void save(const std::string& data) = 0;
};

// 具体实现
class ConsoleLogger : public ILogger {
public:
    void log(const std::string& message) override {
        std::cout << "LOG: " << message << std::endl;
    }
};

class FileLogger : public ILogger {
public:
    void log(const std::string& message) override {
        std::cout << "FILE LOG: " << message << std::endl;
    }
};

class SQLDatabase : public IDatabase {
public:
    void save(const std::string& data) override {
        std::cout << "Saving to SQL: " << data << std::endl;
    }
};

class NoSQLDatabase : public IDatabase {
public:
    void save(const std::string& data) override {
        std::cout << "Saving to NoSQL: " << data << std::endl;
    }
};

// 使用依赖的类
class UserService {
private:
    std::shared_ptr<ILogger> logger;
    std::shared_ptr<IDatabase> database;

public:
    // 构造函数注入
    UserService(std::shared_ptr<ILogger> log, std::shared_ptr<IDatabase> db)
        : logger(log), database(db) {}

    // Setter 注入
    void setLogger(std::shared_ptr<ILogger> log) { logger = log; }
    void setDatabase(std::shared_ptr<IDatabase> db) { database = db; }

    void createUser(const std::string& userData) {
        logger->log("Creating user: " + userData);
        database->save(userData);
        logger->log("User created successfully");
    }
};

// 简单的 DI 容器
class DIContainer {
private:
    std::map<std::string, std::shared_ptr<void>> services;

public:
    template<typename Interface, typename Implementation>
    void registerService() {
        services[typeid(Interface).name()] = std::make_shared<Implementation>();
    }

    template<typename T>
    std::shared_ptr<T> resolve() {
        auto it = services.find(typeid(T).name());
        if (it != services.end()) {
            return std::static_pointer_cast<T>(it->second);
        }
        return nullptr;
    }
};

// 使用示例
void dependencyInjectionExample() {
    // 手动依赖注入
    auto logger = std::make_shared<ConsoleLogger>();
    auto database = std::make_shared<SQLDatabase>();
    UserService userService(logger, database);
    userService.createUser("John Doe");

    // 使用 DI 容器
    DIContainer container;
    container.registerService<ILogger, FileLogger>();
    container.registerService<IDatabase, NoSQLDatabase>();
    auto logger2 = container.resolve<ILogger>();
    auto database2 = container.resolve<IDatabase>();
    if (logger2 && database2) {
        UserService userService2(logger2, database2);
        userService2.createUser("Jane Smith");
    }
}

98. 代码组织和模块化?

良好的代码组织和模块化。分层架构(表示层、业务层、数据层),模块划分按功能职责,接口设计清晰的模块边界。

// 数据访问层
namespace DataAccess {
class IRepository {
public:
    virtual ~IRepository() = default;
    virtual void save(const std::string& data) = 0;
    virtual std::string load(int id) = 0;
};

class UserRepository : public IRepository {
public:
    void save(const std::string& data) override {
        std::cout << "Saving user to database: " << data << std::endl;
    }
    std::string load(int id) override {
        return "User data for ID: " + std::to_string(id);
    }
};
}

// 业务逻辑层
namespace BusinessLogic {
class UserService {
private:
    std::shared_ptr<DataAccess::IRepository> repository;

public:
    UserService(std::shared_ptr<DataAccess::IRepository> repo) : repository(repo) {}

    bool createUser(const std::string& userData) {
        if (userData.empty()) return false;
        repository->save(userData);
        return true;
    }

    std::string getUser(int id) {
        return repository->load(id);
    }
};

class ValidationService {
public:
    bool validateEmail(const std::string& email) {
        return email.find('@') != std::string::npos;
    }
    bool validatePassword(const std::string& password) {
        return password.length() >= 8;
    }
};
}

// 表示层
namespace Presentation {
class UserController {
private:
    std::shared_ptr<BusinessLogic::UserService> userService;
    std::shared_ptr<BusinessLogic::ValidationService> validationService;

public:
    UserController(
        std::shared_ptr<BusinessLogic::UserService> userSvc,
        std::shared_ptr<BusinessLogic::ValidationService> validationSvc)
        : userService(userSvc), validationService(validationSvc) {}

    void registerUser(const std::string& email, const std::string& password) {
        if (!validationService->validateEmail(email)) {
            std::cout << "Invalid email format" << std::endl;
            return;
        }
        if (!validationService->validatePassword(password)) {
            std::cout << "Password too short" << std::endl;
            return;
        }
        std::string userData = "Email: " + email + ", Password: " + password;
        if (userService->createUser(userData)) {
            std::cout << "User registered successfully" << std::endl;
        } else {
            std::cout << "Failed to register user" << std::endl;
        }
    }
};
}

// 应用程序入口
void modularExample() {
    // 初始化各层
    auto repository = std::make_shared<DataAccess::UserRepository>();
    auto userService = std::make_shared<BusinessLogic::UserService>(repository);
    auto validationService = std::make_shared<BusinessLogic::ValidationService>();
    auto userController = std::make_shared<Presentation::UserController>(
        userService, validationService);

    // 使用
    userController->registerUser("[email protected]", "password123");
    userController->registerUser("invalid-email", "short");
}

99. 测试驱动开发 (TDD)?

TDD 开发流程:编写测试(先写失败的测试)、运行测试(确认失败)、编写代码(最小化代码使测试通过)、重构(优化代码保持测试通过)。

// 测试框架简化版
#define ASSERT_TRUE(condition) \nif (!(condition)) { \n    std::cout << "FAIL: " << #condition << " at line " << __LINE__ << std::endl; \n} else { \n    std::cout << "PASS: " << #condition << std::endl; \n}
#define ASSERT_EQ(expected, actual) \nif ((expected) != (actual)) { \n    std::cout << "FAIL: expected " << (expected) << " but got " << (actual) << " at line " << __LINE__ << std::endl; \n} else { \n    std::cout << "PASS: " << (expected) << " == " << (actual) << std::endl; \n}

// TDD 示例:计算器类
class Calculator {
public:
    int add(int a, int b) { return a + b; }
    int subtract(int a, int b) { return a - b; }
    int multiply(int a, int b) { return a * b; }
    double divide(int a, int b) {
        if (b == 0) throw std::runtime_error("Division by zero");
        return static_cast<double>(a) / b;
    }
};

// 测试用例
void testCalculator() {
    Calculator calc;
    // 测试加法
    ASSERT_EQ(5, calc.add(2, 3));
    ASSERT_EQ(0, calc.add(-2, 2));
    ASSERT_EQ(-5, calc.add(-2, -3));
    // 测试减法
    ASSERT_EQ(1, calc.subtract(3, 2));
    ASSERT_EQ(-1, calc.subtract(2, 3));
    // 测试乘法
    ASSERT_EQ(6, calc.multiply(2, 3));
    ASSERT_EQ(0, calc.multiply(2, 0));
    // 测试除法
    ASSERT_EQ(2.0, calc.divide(4, 2));
    ASSERT_EQ(1.5, calc.divide(3, 2));
    // 测试除零异常
    try {
        calc.divide(1, 0);
        ASSERT_TRUE(false); // 不应该到达这里
    } catch (const std::runtime_error&) {
        ASSERT_TRUE(true); // 期望的异常
    }
}

// TDD 流程示例
class Stack {
private:
    std::vector<int> data;

public:
    void push(int item) { data.push_back(item); }
    int pop() {
        if (data.empty()) {
            throw std::runtime_error("Stack is empty");
        }
        int item = data.back();
        data.pop_back();
        return item;
    }
    bool isEmpty() const { return data.empty(); }
    int size() const { return data.size(); }
};

void testStack() {
    Stack stack;
    // 测试空栈
    ASSERT_TRUE(stack.isEmpty());
    ASSERT_EQ(0, stack.size());
    // 测试 push
    stack.push(1);
    ASSERT_FALSE(stack.isEmpty());
    ASSERT_EQ(1, stack.size());
    stack.push(2);
    ASSERT_EQ(2, stack.size());
    // 测试 pop
    ASSERT_EQ(2, stack.pop());
    ASSERT_EQ(1, stack.size());
    ASSERT_EQ(1, stack.pop());
    ASSERT_TRUE(stack.isEmpty());
    // 测试空栈 pop 异常
    try {
        stack.pop();
        ASSERT_TRUE(false);
    } catch (const std::runtime_error&) {
        ASSERT_TRUE(true);
    }
}

// 运行测试
void runTests() {
    std::cout << "=== Calculator Tests ===" << std::endl;
    testCalculator();
    std::cout << "\n=== Stack Tests ===" << std::endl;
    testStack();
}

100. C++ 最佳实践总结?

C++ 开发最佳实践:

代码风格

  • 使用一致的命名约定
  • 保持函数和类的职责单一
  • 添加适当的注释和文档
  • 遵循项目编码规范

内存管理

  • 优先使用智能指针
  • 遵循 RAII 原则
  • 避免内存泄漏和野指针
  • 合理使用移动语义

性能优化

  • 选择合适的容器和算法
  • 避免不必要的拷贝
  • 使用编译期优化
  • 进行性能分析

错误处理

  • 使用异常处理错误情况
  • 提供清晰的错误信息
  • 保证异常安全
  • 合理使用 noexcept

现代 C++ 特性

  • 使用 auto 简化代码
  • 利用范围 for 循环
  • 使用 lambda 表达式
  • 采用智能指针管理资源

设计原则

  • 遵循 SOLID 原则
  • 使用设计模式解决常见问题
  • 保持代码的可测试性
  • 考虑代码的可维护性
// 最佳实践示例
class ModernCppExample {
private:
    std::unique_ptr<int[]> data_;
    size_t size_;

public:
    // 使用智能指针和移动语义
    ModernCppExample(size_t size) : size_(size) {
        data_ = std::make_unique<int[]>(size_);
        std::fill_n(data_.get(), size_, 0);
    }

    // 使用默认的拷贝/移动操作
    ModernCppExample(const ModernCppExample&) = delete;
    ModernCppExample& operator=(const ModernCppExample&) = delete;
    ModernCppExample(ModernCppExample&&) = default;
    ModernCppExample& operator=(ModernCppExample&&) = default;

    // 使用 const 和 noexcept
    size_t size() const noexcept { return size_; }

    // 使用范围 for 循环友好的接口
    int* begin() { return data_.get(); }
    int* end() { return data_.get() + size_; }
    const int* begin() const { return data_.get(); }
    const int* end() const { return data_.get() + size_; }

    // 使用异常处理
    void at(size_t index, int value) {
        if (index >= size_) {
            throw std::out_of_range("Index out of range");
        }
        data_[index] = value;
    }

    // 使用 constexpr 和 auto
    constexpr static size_t max_size() noexcept { return 1000000; }
};

// 使用示例
void bestPracticeExample() {
    try {
        ModernCppExample example(10);
        // 使用 auto 和范围 for 循环
        for (auto& item : example) {
            item = 42;
        }
        // 使用 STL 算法
        std::sort(example.begin(), example.end());
        std::cout << "Size: " << example.size() << std::endl;
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }
}

总结

这 100 道 C++ 面试题涵盖了现代 C++ 开发的核心知识点:

核心技能
  • 基础语法:面向对象、继承多态、运算符重载
  • 现代特性:智能指针、lambda、移动语义、并发编程
  • STL 精通:容器、算法、迭代器、函数对象
  • 设计模式:常用模式的理解和应用
进阶能力
  • 内存管理:RAII、智能指针、异常安全
  • 性能优化:移动语义、编译期优化、缓存友好
  • 并发编程:线程、互斥锁、原子操作、异步编程
  • 架构设计:SOLID 原则、依赖注入、模块化
面试准备建议
  1. 理解原理:不要死记硬背,理解底层机制
  2. 动手实践:多写代码,积累实际经验
  3. 关注现代 C++:掌握 C++11/14/17/20 新特性
  4. 项目经验:结合实际项目理解概念
  5. 持续学习:C++ 标准不断更新,保持学习

目录

  1. C++ 经典面试题精选
  2. 第一部分:C++ 基础语法
  3. 面向对象基础
  4. 访问控制与封装
  5. 继承与多态
  6. 运算符重载
  7. 第二部分:C++ 核心特性
  8. 模板编程
  9. STL 容器
  10. STL 算法
  11. 智能指针
  12. 第三部分:内存管理与性能
  13. 内存管理
  14. 异常处理
  15. 性能优化
  16. 编译时添加调试信息
  17. 运行程序生成 gmon.out
  18. 分析性能数据
  19. 使用 perf 分析
  20. 第四部分:高级特性
  21. 多线程编程
  22. 现代 C++ 特性
  23. 第五部分:设计模式与架构
  24. 设计模式
  25. 架构设计
  26. 总结
  27. 核心技能
  28. 进阶能力
  29. 面试准备建议
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • AMD 显卡 llama.cpp Vulkan 后端兼容与优化指南
  • Vue3+Spring Boot 若依 RuoYi-Vue3 快速搭建企业级后台
  • C++ 类与对象核心知识点总结
  • Whisper v0.2 本地语音转文字工具安装与使用指南
  • Stable Diffusion 3.5 WebUI Forge 与 SwarmUI 实战指南
  • Python 爬虫实战:爬取汽车之家车型与报价数据
  • 2026 AI智能图+AI视频终极工具箱:10个必备神器合集
  • Claude Code 中 CLAUDE.md 的加载时机与书写最佳实践
  • Linux 进程间通信:命名管道(FIFO)实战指南
  • VR 多相电源架构与设计详解
  • 判断一个需求值不值得做:产品经理的评估思路
  • 正版 Adobe PS 与 LRC AI 填充功能无法使用解决方案
  • OpenCode 安装 oh-my-opencode 插件教程:AI 辅助自动安装
  • 深入理解飞书 Webhook 签名验证:一次踩坑到填坑的完整记录
  • LightRAG:轻量级 RAG 模型构建知识库问答系统
  • C++ 快读快写技术详解
  • OpenClaw 在 WSL Ubuntu 及 CentOS 虚拟机安装与飞书对接教程
  • 知网 AIGC 检测算法 2026 升级:新规则解读与应对策略
  • 解决传感器数据漂移问题:零点校准算法与温度漂移补偿
  • 开源大模型与闭源大模型的区别及选择指南

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online