C++简介

C++ 是一种静态类型的、编译式的、通用的、大小写敏感的、不规则的编程语言,支持过程化编程、面向对象编程和泛型编程。

C++ 是 C 的一个超集,事实上,任何合法的 C 程序都是合法的 C++ 程序。

四大特性

C++ 完全支持面向对象的程序设计,包括面向对象开发的四大特性:

标准库

标准的 C++ 由三个重要部分组成:
核心语言,提供了所有构件块,包括变量、数据类型和常量,等等。
C++ 标准库,提供了大量的函数,用于操作文件、字符串等。
标准模板库(STL),提供了大量的方法,用于操作数据结构等。

ANSI 标准

ANSI 标准是为了确保 C++ 的便携性 —— 您所编写的代码在 Mac、UNIX、Windows、Alpha 计算机上都能通过编译。

由于 ANSI 标准已稳定使用了很长的时间,所有主要的 C++ 编译器的制造商都支持 ANSI 标准。

C++语言结构

实例
#include <iostream>
using namespace std;
 
// main() 是程序开始执行的地方
 
int main()
{
   cout << "Hello World"; // 输出 Hello World
   return 0;
}

C++ 语言定义了一些头文件,这些头文件包含了程序中必需的或有用的信息。上面这段程序中,包含了头文件 <iostream>。
下一行 using namespace std; 告诉编译器使用 std 命名空间。命名空间是 C++ 中一个相对新的概念。
下一行 // main() 是程序开始执行的地方 是一个单行注释。单行注释以 // 开头,在行末结束。

基本概念

C++数据类型
注意:默认情况下,int、short、long都是带符号的,即 signed。

注意:long int 8 个字节,int 都是 4 个字节

C++指针

地址思维:指针存储的是地址,不是值本身
类型匹配:指针类型必须与指向的数据类型匹配
生命周期管理:确保指针有效期间指向的内存也有效
现代实践:优先使用智能指针,避免裸指针的内存管理问题

智能指针(smart pointer)是封装了“裸指针”的类模板,利用 RAII 在对象生命周期结束时自动释放资源,从根本上防止内存泄漏和悬空指针。
C++11 之后标准库主要提供三种:

除了智能指针,C++ 里常见的“指针”类别还有:

C++ 引用 vs 指针
引用变量是一个别名,也就是说,它是某个已存在变量的另一个名字。
一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量。
引用必须在定义时初始化,并且一旦绑定到一个变量后,就不能再绑定到其他变量。

引用很容易与指针混淆,它们之间有三个主要的不同:

不存在空引用,引用必须连接到一块合法的内存。
一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
引用必须在创建时被初始化。指针可以在任何时间被初始化。
引用的对象必须是一个变量,而指针必须是一个地址。

C++结构体
结构体是 C++ 中另一种用户自定义的可用的数据类型,它允许您存储不同类型的数据项。
结构用于表示一条记录,假设您想要跟踪图书馆中书本的动态,您可能需要跟踪每本书的下列属性。

结构体优点:

简单数据封装:适合封装多种类型的简单数据,通常用于数据的存储。
轻量级:相比 class,结构体语法更简洁,适合小型数据对象。
面向对象支持:支持构造函数、成员函数和访问权限控制,可以实现面向对象的设计。

C++构造函数

Details

#constexpr构造函数(C++11+)

编译时计算的构造函数

用于创建常量表达式对象
class MyClass {
public:
    // 1. 默认构造函数(无参数)
    MyClass() {
        // 初始化代码
    }
    
    // 2. 参数化构造函数
    MyClass(int x, int y) {
        this->x = x;
        this->y = y;
    }
    
    // 3. 拷贝构造函数
    MyClass(const MyClass& other) {
        this->x = other.x;
        this->y = other.y;
    }
    
    // 4. 移动构造函数(C++11)
    MyClass(MyClass&& other) noexcept {
        this->x = std::move(other.x);
        this->y = std::move(other.y);
    }
    
    // 5. 委托构造函数(C++11)
    MyClass(int x) : MyClass(x, 0) {
        // 委托给两个参数的构造函数
    }
    
    // 6. 转换构造函数(单参数)
    MyClass(int x) {
        this->x = x;
    }
    
    // 7. 继承中的构造函数
    class Derived : public Base {
    public:
        // 使用using声明继承基类构造函数(C++11)
        using Base::Base;
        
        // 或显式调用基类构造函数
        Derived(int x, int y) : Base(x), y(y) {}
    };

private:
    int x, y;
};

析构函数
析构函数是类的特殊成员函数,在对象生命周期结束时自动调用,用于清理资源。函数名:~ + 类名。无参数,无返回值

派生类
派生类(Derived Class)是通过继承(inheritance)从基类(Base Class)创建的新类。获得基类的所有成员(除构造函数、析构函数、私有成员),可以添加新成员,可以修改(重写)继承的方法,是基类的特化版本。

函数重载
函数重载:同一个类中,函数名相同,参数列表不同

C+++基础问题

一、基础篇(校招/初中级 90% 覆盖率)

  1. new/delete 与 malloc/free 区别
    答纲:new 调用构造函数、返回类型安全、不可重载;malloc 只干内存分配。
  2. 指针与引用区别
    答纲:引用必须初始化且不可改指向;指针可空可改可算术。
  3. struct 与 class 区别
    答纲:默认访问级别不同(public vs private),其余一样。
  4. const 与 #define 差异
    答纲:const 有类型/作用域/调试信息;宏纯文本替换。
  5. static 关键字 3 种用法
    答纲:文件内链接、函数内静态变量、类静态成员/函数。
  6. C++ 四种类型转换
    答纲:static_const 编译期;dynamic_cast 运行时多态;const_cast 去常性;reinterpret_cast 最低级位模式。
  7. 深拷贝 vs 浅拷贝
    答纲:深拷贝重新分配资源,浅拷贝只复制指针值。
  8. 拷贝构造函数何时被调用
    答纲:对象以值传参、以值返回、显式拷贝初始化。
  9. 赋值运算符与拷贝构造区别
    答纲:拷贝构造是从无到有;赋值是改写已有对象。
  10. vector/list/deque 复杂度对比
    答纲:随机访问 O(1)/O(n)/O(1);中间插入 O(n)/O(1)/O(n)。
  11. map 与 unordered_map 差异
    答纲:红黑树 vs 哈希表;有序 vs 无序;O(logN) vs 平均 O(1)。
  12. RAII 思想
    答纲:资源获取即初始化,利用对象生命周期管理资源,异常安全。
  13. 构造函数能否是虚函数?
    答纲:不能,对象还没构造完无虚表。
  14. 析构函数何时必须虚?
    答纲:类会被继承且可能通过基类指针删除派生对象。
  15. 重载、重写、隐藏对比
    答纲:同一作用域参数不同→重载;派生类改虚函数→重写;派生类同名非虚→隐藏。

C++高级

  1. 虚函数表与动态分派机制
    答纲:每个多态类一张 vtable,对象首地址前 8 字节存 vptr,运行时查表定位函数。
  2. 模板实例化与代码膨胀控制
    答纲:显式实例化、common_type 技巧、extern template 声明。
  3. SFINAE 与 enable_if 写法
    答纲:替换失败不是错误,用于模板重载决议;C++17 后用 if constexpr 替代。
  4. move 语义完美转发实现
    答纲:std::move 强制右值引用,std::forward 保持值类别,配合引用折叠规则。
  5. 内存模型与 std::memory_order
    答纲:六种顺序,relaxed/acquire/release/acq_rel/seq_cst;无锁队列用 acq/rel 保证可见性。
  6. ABA 问题及解决
    答纲:CAS 检查值相同但已改回;用版本号/双宽 CAS/ hazard pointer。
  7. shared_ptr 控制块与循环引用
    答纲:引用计数+弱引用计数;weak_ptr 打破循环;make_shared 一次分配优化。
  8. chrono 与 自定义时钟
    答纲:steady_clock 单调、system_clock 可映射日历;可写自己的 clock 满足 TrivialClock。
  9. 协程(C++20 co_await)状态机
    答纲:compiler 生成 promise_type、coroutine_frame、挂起点恢复点;注意对称转移。
  10. 零开销抽象反例
    答纲:std::function 动态分配+类型擦除,虚函数调用无法内联;function_ref 替代方案。
  11. consteval/constinit 区别
    答纲:consteval 强制编译期求值,constinit 只保证静态初始化线程安全。
  12. 模块化(C++20 Modules)解决什么问题
    答纲:替代头文件,减少重复解析,提供 BMI 二进制接口,缩短构建时间。
  13. 设计一个线程池——任务窃取如何实现
    答纲:每个线程本地双端队列,pop 从队尾 steal 从队头,减少竞争;用 std::atomic 索引。
  14. placement new 与显式析构顺序
    答纲:先构造数组再逐个析构,需手动调用析构函数,再 operator delete(p, buf)。

C++中内存泄漏问题

问题类型 典型症状 解决方案
堆内存泄漏 RSS 持续增长,OOM 1. 使用 ASan/Valgrind 找到未 delete 处
2. 改用智能指针 (std::unique_ptr, std::shared_ptr)
3. 检查循环引用 (weak_ptr)
资源句柄泄漏 FD 耗尽,Socket 连不上 1. 检查 open/socket 后未 close
2. 使用 RAII 封装文件描述符
内存碎片化 内存总和使用不高,但 malloc 失败 1. 更换分配器 (Jemalloc/TCMalloc)
2. 避免频繁分配大小不一的小对象 (使用内存池)
Cache Miss 高 CPU 利用率低,Stall 高 1. 优化数据结构布局 (连续内存替代链表)
2. 循环分块 (Loop Tiling)
3. 数据预取
NUMA 失衡 多核扩展性差,延迟抖动 1. 绑定线程与内存 (numactl)
2. 使用 mbind 本地分配
伪共享 多线程计数器等原子操作极慢 1. 关键变量添加 alignas(64) 填充