拿捏C++
一、 基础语法与程序结构地基1. 引用Reference场景函数传参时如果想修改实参或者避免大对象拷贝就用引用。cpp#include iostream using namespace std; // 传引用直接修改实参 void swapValue(int a, int b) { int temp a; a b; b temp; } int main() { int x 10, y 20; // 1. 基本用法引用必须初始化且不能改绑 int ref_x x; // ref_x 是 x 的别名 ref_x 100; // 此时 x 也变成 100 // 2. 函数传参 swapValue(x, y); // x20, y10因为传的是引用实参被改了 cout x x , y y endl; return 0; }2. 内存分区堆与栈场景需要动态决定大小时比如数组大小运行时才确定必须用堆。cppvoid memoryDemo() { // 栈区自动释放局部变量 int stack_arr[10]; // 大小必须编译时已知 // 堆区手动释放用 new 申请 int n; cout 请输入数组大小: ; cin n; int* heap_arr new int[n]; // 堆上申请 n 个 int for(int i0; in; i) { heap_arr[i] i * 10; } // ⚠️ 重要必须手动释放否则内存泄漏 delete[] heap_arr; // 如果 new 的是单个对象: delete heap_arr; }二、 面向对象核心OOP—— 重点多态1. 继承与构造/析构顺序cppclass Base { public: Base() { cout 构造 Base endl; } virtual ~Base() { cout 析构 Base endl; } // 虚析构后面讲 }; class Derived : public Base { public: Derived() { cout 构造 Derived endl; } ~Derived() { cout 析构 Derived endl; } }; int main() { Derived d; // 输出顺序构造 Base - 构造 Derived - 析构 Derived - 析构 Base // 规则先父后子构造先子后父析构 return 0; }2. 多态⭐面试必手写核心virtual关键字父类指针/引用指向子类对象调用子类的重写函数。cppclass Animal { public: // 虚函数允许子类重写 virtual void speak() { cout 动物叫 endl; } // 虚析构保证 delete 父类指针时子类析构函数被调用 virtual ~Animal() {} }; class Cat : public Animal { public: void speak() override { // override 是 C11 关键字表重写 cout 喵喵喵 endl; } }; class Dog : public Animal { public: void speak() override { cout 汪汪汪 endl; } }; // 多态核心函数接收父类引用 void letSpeak(Animal animal) { animal.speak(); // 运行时决定具体调 Cat 还是 Dog 的 speak } int main() { Cat cat; Dog dog; letSpeak(cat); // 输出喵喵喵 letSpeak(dog); // 输出汪汪汪 // 用父类指针指向子类对象常用于容器存放异类对象 Animal* ptr new Cat(); ptr-speak(); // 输出喵喵喵 delete ptr; // 如果父类析构不是 virtual这里会内存泄漏只析构父类不析构子类 return 0; }三、 进阶高级特性C的灵魂1. 智能指针RAII—— 告别手动delete场景防止内存泄漏异常安全。开发必须用智能指针代替裸指针。cpp#include memory // 必须引入 class Resource { public: Resource() { cout 资源获取 endl; } ~Resource() { cout 资源释放 endl; } void work() { cout 工作中... endl; } }; void smartPointerDemo() { // 1. unique_ptr独占不能拷贝只能移动 unique_ptrResource ptr1 make_uniqueResource(); // unique_ptrResource ptr2 ptr1; // ❌ 编译报错不允许拷贝 unique_ptrResource ptr2 move(ptr1); // ✅ 转移所有权ptr1 变为空 ptr2-work(); // 2. shared_ptr共享引用计数计数归零时自动释放 shared_ptrResource sp1 make_sharedResource(); shared_ptrResource sp2 sp1; // 引用计数变为 2 cout 引用计数: sp1.use_count() endl; // 输出 2 // 离开作用域sp1和sp2析构计数归零自动delete资源 } int main() { smartPointerDemo(); // 资源自动释放无需手动 delete return 0; }2. 类型转换强制转换原则不用 C 风格的(int)a用 C 的四种转换。cpp// 1. static_cast最常用基本类型、父转子类不安全但允许 int i 10; double d static_castdouble(i); // 2. dynamic_cast安全向下转型父类转子类运行时检查失败返回 nullptr Animal* ani new Cat(); Cat* cat_ptr dynamic_castCat*(ani); // 成功 Dog* dog_ptr dynamic_castDog*(ani); // 失败返回 nullptr因为 ani 实际是 Cat // 3. const_cast去掉 const 属性极少用 const int num 5; int* mod const_castint*(num); // 危险仅用于对付老API // 4. reinterpret_cast最危险强转指针类型底层操作才用 long long address reinterpret_castlong long(ani);四、 现代CC11/14/17/20 必会新特性1. 自动类型推导auto和decltype场景迭代器、模板编程避免写冗长类型。cpp#include vector vectorint vec {1,2,3,4}; // 不用写 vectorint::iteratorauto 自动推 for (auto it vec.begin(); it ! vec.end(); it) { cout *it ; } // 范围 for 循环配合 auto for (auto val : vec) { // 用引用避免拷贝且可修改原值 val * 2; }2. Lambda 表达式匿名函数场景作为回调、STL 算法自定义排序。cpp#include algorithm #include vector int main() { vectorint nums {5, 2, 8, 1, 9}; // 语法[捕获列表](参数列表) - 返回类型 { 函数体 } // 降序排序 sort(nums.begin(), nums.end(), [](int a, int b) - bool { return a b; }); // 捕获外部变量[]值捕获[]引用捕获 int threshold 5; auto count count_if(nums.begin(), nums.end(), [](int x) { return x threshold; // 引用捕获 threshold可以读取 }); cout 大于5的个数: count endl; return 0; }3. 移动语义Move Semantics与std::move核心将资源从“旧对象”偷过来给“新对象”避免深拷贝极大提升性能尤其是vector扩容。cpp#include string #include vector class MyString { char* data; public: // 移动构造函数核心 MyString(MyString other) noexcept : data(other.data) { other.data nullptr; // 置空源指针防止双重释放 } }; // 使用场景 vectorstring vec; string str Hello World; vec.push_back(str); // 拷贝将 str 复制一份放入 vector vec.push_back(std::move(str)); // 移动直接将 str 的内部指针偷走str 变为空 cout str.empty(); // 输出 1 (true)因为 str 已被掏空五、 STL标准模板库高频容器容器底层结构适用场景注意事项vector动态数组尾部增删、随机访问扩容会导致迭代器失效shrink_to_fit()缩容list双向链表频繁中间插入/删除不支持随机访问[]deque双端队列头尾增删支持[]但性能略逊于 vectormap/unordered_map红黑树 / 哈希表键值对查找map有序按keyunordered_map更快O(1)set/unordered_set红黑树 / 哈希表去重、快速判存元素不可修改改了会破坏结构STL 算法示例配合 Lambdacppvectorint v {1,2,3,4,5}; // 查找第一个大于3的元素 auto it find_if(v.begin(), v.end(), [](int x){ return x 3; }); if (it ! v.end()) cout 找到: *it endl; // 输出 4六、 编译与链接隐蔽但重要的坑头文件卫士防止重复包含必须用#pragma once或#ifndef ... #define ... #endif。extern关键字告诉编译器变量在别的文件定义用于跨文件使用全局变量。动态库 vs 静态库.lib/.a静态库编译时嵌入 exe体积大。.dll/.so动态库运行时加载体积小可更新。