[C.C++] C++全体系知识详解(从入门到精通,含设计模式+实战技巧)

494 0
Honkers 2026-3-28 07:45:12 来自手机 | 显示全部楼层 |阅读模式

大家好~ 今天开启一篇C++全体系博客,核心是帮大家全面吃透C++,从基础语法、核心特性,到进阶知识点、常用设计模式,再到实战技巧与避坑指南,覆盖新手入门、进阶提升、工程实战全场景。无论你是刚接触C++的新手,还是有一定基础想系统梳理知识体系的开发者,这篇博客都能帮你查漏补缺、夯实能力。

C++作为一门兼顾性能与灵活性的语言,既能用于底层开发(操作系统、嵌入式),也能用于高层应用(游戏、后端),其核心优势在于高效性和面向对象特性,而设计模式则是提升代码可读性、可维护性的关键。本文将循序渐进,每一部分都搭配简单易懂的示例代码,避免纯理论堆砌,大家可以跟着敲代码、练手感,有疑问也可以在评论区交流~

一、C++基础核心(入门必掌握,筑牢根基)

C++是在C语言的基础上发展而来,保留了C的高效性和底层访问能力,同时增加了面向对象的特性(封装、继承、多态),这也是C++与C最核心的区别。基础部分是后续所有学习的前提,务必吃透每一个重点。

1. 核心特性:面向对象三大支柱

这是C++的灵魂,也是后续学习设计模式的基础,一定要理解透彻,而不是死记硬背。

  • 封装:将数据(成员变量)和操作数据的方法(成员函数)捆绑在一起,隐藏对象的内部实现细节,只对外提供可访问的接口。比如定义一个“学生”类,将姓名、学号作为私有成员,只提供get/set方法供外部访问,避免数据被随意修改,同时降低代码耦合度。

  • 继承:允许一个类(子类)继承另一个类(父类)的属性和方法,实现代码复用,减少冗余。比如“本科生”类可以继承“学生”类,无需重新定义姓名、学号等共性属性,只需新增“专业”“学制”等特有属性即可。注意区分public、protected、private三种继承方式的访问权限差异:public继承保留父类访问权限,protected继承将父类public转为protected,private继承将父类所有成员转为private。

  • 多态:同一接口,不同实现,分为静态多态(函数重载、运算符重载)和动态多态(虚函数)。动态多态是重点,核心是“父类指针/引用指向子类对象,调用虚函数时,会执行子类的实现”,这也是很多设计模式的核心原理(比如工厂模式、策略模式)。

简单示例(动态多态):

  1. #include <iostream>
  2. using namespace std;
  3. // 父类:动物
  4. class Animal {
  5. public:
  6. // 虚函数,实现动态多态
  7. virtual void speak() {
  8. cout << "动物发出声音" << endl;
  9. }
  10. // 析构函数设为虚函数,避免子类对象析构不彻底
  11. virtual ~Animal() {}
  12. };
  13. // 子类:猫
  14. class Cat : public Animal {
  15. public:
  16. void speak() override { // 重写父类虚函数
  17. cout << "猫咪喵喵叫" << endl;
  18. }
  19. };
  20. // 子类:狗
  21. class Dog : public Animal {
  22. public:
  23. void speak() override {
  24. cout << "小狗汪汪叫" << endl;
  25. }
  26. };
  27. // 测试函数,接收父类引用
  28. void animalSpeak(Animal& animal) {
  29. animal.speak(); // 调用的是子类的实现(动态多态)
  30. }
  31. int main() {
  32. Cat cat;
  33. Dog dog;
  34. animalSpeak(cat); // 输出:猫咪喵喵叫
  35. animalSpeak(dog); // 输出:小狗汪汪叫
  36. return 0;
  37. }
复制代码

2. 基础语法高频考点

这部分是日常编码的基础,看似简单,但容易出错,重点关注以下几点,覆盖所有高频使用场景:

  • 指针与引用:指针是指向内存地址的变量,可空、可重新赋值;引用是变量的别名,不可空、不可重新赋值,必须初始化。实际开发中,引用常用作函数参数(避免拷贝,提升效率),指针常用作动态内存分配(new/delete)。注意避免野指针(未初始化的指针)、内存泄漏(忘记释放new分配的内存)。

  • const关键字:修饰变量(变量不可修改)、修饰指针(const int* 指针指向的值不可改,int* const 指针本身不可改,const int* const 指针及其指向的值均不可改)、修饰成员函数(函数内不可修改成员变量)。

  • 函数重载与运算符重载:函数重载要求“函数名相同,参数列表(个数、类型、顺序)不同”,与返回值无关;运算符重载允许自定义运算符的行为(比如重载+,实现两个自定义类对象的相加),注意不能重载的运算符(::、.*、.、? :)。

  • 动态内存分配:使用new分配内存,delete释放内存(单个对象用delete,数组用delete[]),忘记释放会导致内存泄漏。C++11及以上推荐结合智能指针(shared_ptr、unique_ptr、weak_ptr)使用,自动管理内存,避免内存泄漏。

  • 命名空间(namespace):用于解决命名冲突,将不同的代码模块划分到不同的命名空间中,比如std命名空间(C++标准库)。使用方式:using namespace std;(全局使用)或std::cout(局部使用)。

  • 输入输出(IO流):使用cout输出、cin输入,需包含头文件。常用操作:endl(换行并刷新缓冲区)、setw(设置输出宽度)、fixed(固定小数位数)等。

  • 条件与循环语句:if-else、switch-case(注意break避免穿透)、for、while、do-while,与C语言用法基本一致,新增范围for循环(for (int num : arr)),简化数组/容器遍历。

3. 基础小结

C++基础的核心是“面向对象”,而面向对象的核心是多态,后续所有设计模式、进阶知识点,本质上都是对多态、封装、继承的灵活运用。基础部分不用追求“面面俱到”,但一定要把上述重点吃透,否则学习进阶内容和设计模式时会很吃力——C++的学习没有“捷径”,基础扎实才能走得更远。

二、C++进阶知识点(提升核心能力,适配工程开发)

掌握基础后,需要重点学习进阶知识点,这些内容是工程开发中高频使用的核心能力,也是区分新手和进阶开发者的关键。

1. 智能指针(C++11及以上)

智能指针的核心作用是自动管理动态内存,避免内存泄漏,无需手动调用delete,是C++11后的核心特性之一,常用的有三种:

  • unique_ptr:独占式智能指针,一个对象只能被一个unique_ptr管理,不可拷贝、不可赋值,适合管理单个对象,效率最高。

  • shared_ptr:共享式智能指针,多个shared_ptr可以管理同一个对象,通过引用计数控制对象生命周期,引用计数为0时自动释放内存,适合多线程场景。

  • weak_ptr:弱引用智能指针,不增加引用计数,用于解决shared_ptr的循环引用问题(比如两个对象互相持有shared_ptr,导致引用计数无法为0,内存泄漏)。

示例(shared_ptr使用):

  1. #include <iostream>
  2. #include <memory> // 智能指针头文件
  3. using namespace std;
  4. class Person {
  5. public:
  6. Person(string name) : name(name) {
  7. cout << name << " 构造" << endl;
  8. }
  9. ~Person() {
  10. cout << name << " 析构" << endl;
  11. }
  12. private:
  13. string name;
  14. };
  15. int main() {
  16. // 共享式智能指针,自动管理内存
  17. shared_ptr<Person> p1(new Person("张三"));
  18. shared_ptr<Person> p2 = p1; // 引用计数+1(此时为2)
  19. cout << "引用计数:" << p1.use_count() << endl; // 输出2
  20. p1.reset(); // 释放p1的引用,引用计数-1(变为1)
  21. cout << "引用计数:" << p2.use_count() << endl; // 输出1
  22. // 主函数结束,p2释放,引用计数变为0,对象自动析构
  23. return 0;
  24. }
复制代码

2. STL容器(标准模板库)

STL(Standard Template Library)是C++的核心库,包含容器、算法、迭代器三大部分,极大提升开发效率,无需重复实现常用数据结构和算法。重点掌握以下高频容器:

  • 序列式容器:vector(动态数组,随机访问快,插入删除尾部高效)、list(双向链表,插入删除高效,随机访问慢)、deque(双端队列,兼顾vector和list的优势)。

  • 关联式容器:map(键值对,按键排序,不允许重复键)、unordered_map(键值对,哈希存储,查找效率O(1),不排序)、set(集合,存储唯一元素,按键排序)、unordered_set(集合,哈希存储,查找高效)。

  • 容器适配器:stack(栈,后进先出LIFO)、queue(队列,先进先出FIFO)、priority_queue(优先队列,默认大顶堆)。

示例(vector与map使用):

  1. #include <iostream>
  2. #include <vector>
  3. #include <map>
  4. using namespace std;
  5. int main() {
  6. // vector使用
  7. vector<int> arr = {1, 2, 3, 4, 5};
  8. arr.push_back(6); // 尾部插入
  9. for (int num : arr) { // 范围for循环遍历
  10. cout << num << " ";
  11. }
  12. cout << endl;
  13. // map使用
  14. map<string, int> score;
  15. score["张三"] = 90;
  16. score["李四"] = 85;
  17. // 迭代器遍历
  18. for (map<string, int>::iterator it = score.begin(); it != score.end(); it++) {
  19. cout << it->first << ":" << it->second << endl;
  20. }
  21. return 0;
  22. }
复制代码

3. 异常处理(try-catch-throw)

异常处理用于捕获程序运行时的错误(比如除0、数组越界),避免程序崩溃,提升程序健壮性。核心语法:try(包裹可能出错的代码)、catch(捕获异常并处理)、throw(抛出异常)。

示例(异常处理):

  1. #include <iostream>
  2. using namespace std;
  3. // 除法函数,抛出异常
  4. int divide(int a, int b) {
  5. if (b == 0) {
  6. throw "除0错误!"; // 抛出字符串异常
  7. }
  8. return a / b;
  9. }
  10. int main() {
  11. try {
  12. int result = divide(10, 0);
  13. cout << "结果:" << result << endl;
  14. } catch (const char* err) { // 捕获字符串异常
  15. cout << "异常捕获:" << err << endl;
  16. } catch (...) { // 捕获所有类型异常(兜底)
  17. cout << "未知异常" << endl;
  18. }
  19. return 0;
  20. }
复制代码

4. lambda表达式(C++11及以上)

lambda表达式用于定义匿名函数,简化代码,尤其适合作为函数参数(比如STL算法的回调函数)。语法:[捕获列表](参数列表) mutable noexcept -> 返回值类型 { 函数体 }。

示例(lambda结合STL排序):

  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm> // sort算法头文件
  4. using namespace std;
  5. int main() {
  6. vector<int> arr = {3, 1, 4, 1, 5, 9, 2, 6};
  7. // lambda表达式作为sort的回调函数,实现降序排序
  8. sort(arr.begin(), arr.end(), [](int a, int b) {
  9. return a > b;
  10. });
  11. for (int num : arr) {
  12. cout << num << " ";
  13. }
  14. return 0;
  15. }
复制代码

5. 其他进阶知识点

  • 模板(template):泛型编程的核心,允许编写与类型无关的代码,比如STL容器、算法都是基于模板实现的。分为函数模板和类模板。

  • 右值引用与移动语义(C++11及以上):解决临时对象的拷贝开销,提升效率,核心是“移动”而非“拷贝”,常用关键字:&&(右值引用)、move(将左值转为右值)。

  • constexpr(C++11及以上):用于定义常量表达式,在编译期计算结果,提升程序运行效率。

  • 虚函数表:动态多态的底层实现,父类含有虚函数时,编译器会为其生成虚函数表,子类重写虚函数时,会修改虚函数表中的对应条目,实现“动态绑定”。

三、C++常用设计模式(从原理到实践,高频优先)

设计模式的核心目的是“解耦”,让代码更易维护、易扩展、易复用。最经典的设计模式是Gang of Four(GoF) 总结的23种,很多同学提到的状态机相关模式(状态模式)也包含其中。下面先完整罗列这23种设计模式,按创建型、结构型、行为型三大类分类(便于理解和记忆),再重点讲解C++工程中高频使用的几种,每一种高频模式都包含“核心思想+适用场景+示例代码”,确保大家能看懂、会用;其余模式补充核心说明,方便大家全面了解。

补充:GoF 23种经典设计模式完整列表(按类型分类)

设计模式按用途可分为三大类,各类模式的核心定位不同,下面逐一罗列,重点标注高频使用的模式(加粗),方便大家区分重点:

一、创建型模式(共5种,核心:负责对象的创建,解耦对象创建与使用)
  • 单例模式(Singleton Pattern):保证一个类只有一个实例,提供全局访问点(下文已详解)。

  • 工厂方法模式(Factory Method Pattern):定义创建对象的接口,让子类决定实例化哪个类(下文已详解)。

  • 简单工厂模式(Simple Factory Pattern):由一个工厂类根据参数,动态创建不同产品类的实例(工厂方法模式的简化版),不符合开闭原则,适合简单场景。

  • 抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,无需指定它们具体的类,适用于产品族场景(比如生产手机+耳机的工厂)。

  • 建造者模式(Builder Pattern):将复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示,适合复杂对象的分步构建(比如构建一个包含多种配置的电脑)。

  • 原型模式(Prototype Pattern):用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象,实现对象的快速克隆(比如复制一个已有对象,修改部分属性)。

二、结构型模式(共7种,核心:负责类和对象的组合,优化类结构,实现功能复用)
  • 适配器模式(Adapter Pattern):将一个类的接口转换成客户希望的另一个接口,解决类之间的兼容性问题,让原本不兼容的类可以一起工作(比如将旧接口适配成新接口)。

  • 桥接模式(Bridge Pattern):将抽象部分与它的实现部分分离,使它们都可以独立地变化,实现抽象与实现的解耦(比如将“形状”和“颜色”分离,各自独立扩展)。

  • 装饰器模式(Decorator Pattern):动态地给一个对象添加一些额外的职责,不改变原类结构,比继承更灵活(比如给一杯咖啡添加牛奶、糖等配料)。

  • 迭代器模式(Iterator Pattern):提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露该对象的内部表示(比如STL容器的迭代器)。

  • 组合模式(Composite Pattern):将对象组合成树形结构,以表示“部分-整体”的层次关系,使得用户对单个对象和组合对象的使用具有一致性(比如文件夹和文件的树形结构)。

  • 外观模式(Facade Pattern):为子系统中的一组接口提供一个一致的界面,定义一个高层接口,使得子系统更容易使用(比如一个统一的API接口,封装多个子系统的操作)。

  • 享元模式(Flyweight Pattern):运用共享技术有效地支持大量细粒度的对象,节省内存(比如系统中的字体对象,多个地方共用同一个字体实例)。

三、行为型模式(共11种,核心:负责对象之间的通信,规范对象行为,实现对象间的协作)
  • 策略模式(Strategy Pattern):定义一系列算法,将每个算法封装起来,并且使它们可以相互替换,让算法的变化独立于使用算法的客户(下文已详解)。

  • 观察者模式(Observer Pattern):定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新(比如公众号和订阅者的关系)。

  • 状态模式(State Pattern):允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类(比如电梯的运行状态:停止、上升、下降)。

  • 命令模式(Command Pattern):将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作(比如遥控器的按键命令)。

  • 责任链模式(Chain of Responsibility Pattern):为请求创建一个接收者对象的链,使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系(比如请假审批流程)。

  • 解释器模式(Interpreter Pattern):给定一个语言,定义它的文法的一种表示,并定义一个解释器,使用该表示来解释语言中的句子(比如简单的表达式解析)。

  • 中介者模式(Mediator Pattern):用一个中介对象来封装一系列对象之间的交互,使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互(比如聊天室的中介者)。

  • 备忘录模式(Memento Pattern):在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,以便以后当需要时能将该对象恢复到原先保存的状态(比如游戏存档)。

  • 访问者模式(Visitor Pattern):表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作(比如对不同类型的文件进行不同的操作)。

  • 模板方法模式(Template Method Pattern):定义一个操作中的算法的骨架,而将一些步骤延迟到子类中,使得子类可以不改变算法的结构即可重定义该算法的某些特定步骤(比如一个流程固定,部分步骤可自定义的任务)。

  • 迭代器模式(已在结构型中提及,此处不重复)

1. 单例模式(Singleton Pattern)

核心思想:保证一个类只有一个实例,并提供一个全局访问点,避免频繁创建和销毁对象,节省内存。

适用场景:全局配置类、日志类、数据库连接池等,这类场景需要确保全局只有一个实例,避免数据不一致。

实现要点:私有化构造函数(禁止外部创建对象)、私有化拷贝构造和赋值运算符(禁止拷贝)、提供一个静态成员函数获取实例。

C++推荐实现(线程安全,懒汉式,C++11及以上):

  1. #include <iostream>
  2. using namespace std;
  3. class Singleton {
  4. public:
  5. // 全局访问点,返回唯一实例
  6. static Singleton& getInstance() {
  7. // C++11后,局部静态变量初始化是线程安全的
  8. static Singleton instance;
  9. return instance;
  10. }
  11. // 测试方法
  12. void show() {
  13. cout << "单例模式实例:" << this << endl;
  14. }
  15. private:
  16. // 私有化构造函数,禁止外部创建
  17. Singleton() {}
  18. // 私有化拷贝构造和赋值运算符,禁止拷贝
  19. Singleton(const Singleton&) = delete;
  20. Singleton& operator=(const Singleton&) = delete;
  21. };
  22. // 测试
  23. int main() {
  24. Singleton& s1 = Singleton::getInstance();
  25. Singleton& s2 = Singleton::getInstance();
  26. s1.show();
  27. s2.show(); // 输出地址相同,说明是同一个实例
  28. return 0;
  29. }
复制代码

注意:懒汉式(需要时才创建实例) vs 饿汉式(程序启动时创建实例),日常开发中懒汉式更常用,节省内存;饿汉式无需考虑线程安全,但启动速度稍慢。

2. 工厂模式(Factory Pattern)

核心思想:定义一个创建对象的接口,让子类决定实例化哪个类,将对象的创建与使用分离,降低耦合。

适用场景:当一个类不知道它所需要创建的对象的具体类型,或者需要动态创建不同类型的对象时(比如根据用户输入,创建不同的图形对象:圆形、矩形)。

工厂模式分为三种:简单工厂、工厂方法、抽象工厂,这里重点讲解最常用的工厂方法模式(简单工厂不符合开闭原则,抽象工厂适用于更复杂的场景)。

示例(工厂方法模式,创建不同的图形):

  1. #include <iostream>
  2. using namespace std;
  3. // 抽象产品:图形
  4. class Shape {
  5. public:
  6. virtual void draw() = 0; // 纯虚函数,抽象接口
  7. virtual ~Shape() {}
  8. };
  9. // 具体产品:圆形
  10. class Circle : public Shape {
  11. public:
  12. void draw() override {
  13. cout << "绘制圆形" << endl;
  14. }
  15. };
  16. // 具体产品:矩形
  17. class Rectangle : public Shape {
  18. public:
  19. void draw() override {
  20. cout << "绘制矩形" << endl;
  21. }
  22. };
  23. // 抽象工厂:图形工厂
  24. class ShapeFactory {
  25. public:
  26. virtual Shape* createShape() = 0; // 纯虚函数,创建产品
  27. virtual ~ShapeFactory() {}
  28. };
  29. // 具体工厂:圆形工厂
  30. class CircleFactory : public ShapeFactory {
  31. public:
  32. Shape* createShape() override {
  33. return new Circle();
  34. }
  35. };
  36. // 具体工厂:矩形工厂
  37. class RectangleFactory : public ShapeFactory {
  38. public:
  39. Shape* createShape() override {
  40. return new Rectangle();
  41. }
  42. };
  43. // 测试
  44. int main() {
  45. // 创建圆形工厂,生产圆形
  46. ShapeFactory* circleFactory = new CircleFactory();
  47. Shape* circle = circleFactory->createShape();
  48. circle->draw(); // 输出:绘制圆形
  49. // 创建矩形工厂,生产矩形
  50. ShapeFactory* rectFactory = new RectangleFactory();
  51. Shape* rect = rectFactory->createShape();
  52. rect->draw(); // 输出:绘制矩形
  53. // 释放内存
  54. delete circle;
  55. delete circleFactory;
  56. delete rect;
  57. delete rectFactory;
  58. return 0;
  59. }
复制代码

优势:新增图形(比如三角形)时,只需新增具体产品类和具体工厂类,无需修改原有代码,符合“开闭原则”(对扩展开放,对修改关闭)。

3. 策略模式(Strategy Pattern)

核心思想:定义一系列算法,将每个算法封装起来,并且使它们可以相互替换,让算法的变化独立于使用算法的客户。

适用场景:一个类有多种行为,且这些行为可以动态切换(比如排序算法:冒泡排序、快速排序、选择排序,根据需求动态切换)。

示例(策略模式,实现不同的排序算法):

  1. #include <iostream>
  2. #include <vector>
  3. using namespace std;
  4. // 抽象策略:排序算法
  5. class SortStrategy {
  6. public:
  7. virtual void sort(vector<int>& arr) = 0;
  8. virtual ~SortStrategy() {}
  9. };
  10. // 具体策略1:冒泡排序
  11. class BubbleSort : public SortStrategy {
  12. public:
  13. void sort(vector<int>& arr) override {
  14. int n = arr.size();
  15. for (int i = 0; i < n - 1; i++) {
  16. for (int j = 0; j < n - i - 1; j++) {
  17. if (arr[j] > arr[j + 1]) {
  18. swap(arr[j], arr[j + 1]);
  19. }
  20. }
  21. }
  22. cout << "冒泡排序完成" << endl;
  23. }
  24. };
  25. // 具体策略2:快速排序(简化版)
  26. class QuickSort : public SortStrategy {
  27. public:
  28. void sort(vector<int>& arr) override {
  29. quickSort(arr, 0, arr.size() - 1);
  30. cout << "快速排序完成" << endl;
  31. }
  32. private:
  33. void quickSort(vector<int>& arr, int left, int right) {
  34. if (left >= right) return;
  35. int pivot = arr[left];
  36. int i = left, j = right;
  37. while (i != j) {
  38. while (arr[j] >= pivot && i < j) j--;
  39. while (arr[i] <= pivot && i < j) i++;
  40. if (i < j) swap(arr[i], arr[j]);
  41. }
  42. swap(arr[left], arr[i]);
  43. quickSort(arr, left, i - 1);
  44. quickSort(arr, i + 1, right);
  45. }
  46. };
  47. // 环境类:使用排序策略
  48. class Sorter {
  49. private:
  50. SortStrategy* strategy; // 持有策略对象
  51. public:
  52. // 设置策略(动态切换)
  53. void setStrategy(SortStrategy* s) {
  54. delete strategy; // 释放原有策略
  55. strategy = s;
  56. }
  57. // 执行排序
  58. void sort(vector<int>& arr) {
  59. if (strategy) strategy->sort(arr);
  60. }
  61. ~Sorter() {
  62. delete strategy;
  63. }
  64. };
  65. // 测试
  66. int main() {
  67. vector<int> arr = {3, 1, 4, 1, 5, 9, 2, 6};
  68. Sorter sorter;
  69. // 使用冒泡排序
  70. sorter.setStrategy(new BubbleSort());
  71. sorter.sort(arr);
  72. for (int num : arr) cout << num << " ";
  73. cout << endl;
  74. // 动态切换为快速排序
  75. sorter.setStrategy(new QuickSort());
  76. sorter.sort(arr);
  77. for (int num : arr) cout << num << " ";
  78. cout << endl;
  79. return 0;
  80. }
复制代码

优势:算法可以独立于使用它的客户,新增算法时无需修改环境类,只需新增具体策略类,同时支持动态切换算法,灵活性极高。

4. 观察者模式(Observer Pattern)

核心思想:定义对象间的一对多依赖关系,当被观察者(主题)的状态发生改变时,所有依赖它的观察者都会收到通知,并自动更新自己的状态。

适用场景:公众号与订阅者、天气预报系统、消息通知系统等,需要实现“一处变化,多处响应”的场景。

示例(观察者模式:公众号与订阅者):

  1. #include <iostream>
  2. #include <vector>
  3. #include <string>
  4. using namespace std;
  5. // 抽象观察者
  6. class Observer {
  7. public:
  8. virtual void update(string message) = 0; // 接收通知并更新
  9. virtual ~Observer() {}
  10. };
  11. // 具体观察者:订阅者
  12. class Subscriber : public Observer {
  13. private:
  14. string name;
  15. public:
  16. Subscriber(string name) : name(name) {}
  17. void update(string message) override {
  18. cout << name << " 收到消息:" << message << endl;
  19. }
  20. };
  21. // 抽象被观察者(主题)
  22. class Subject {
  23. public:
  24. virtual void attach(Observer* observer) = 0; // 添加观察者
  25. virtual void detach(Observer* observer) = 0; // 移除观察者
  26. virtual void notify(string message) = 0; // 通知所有观察者
  27. virtual ~Subject() {}
  28. };
  29. // 具体被观察者:公众号
  30. class WeChatOfficialAccount : public Subject {
  31. private:
  32. vector<Observer*> observers; // 存储所有观察者
  33. public:
  34. void attach(Observer* observer) override {
  35. observers.push_back(observer);
  36. }
  37. void detach(Observer* observer) override {
  38. for (auto it = observers.begin(); it != observers.end(); it++) {
  39. if (*it == observer) {
  40. observers.erase(it);
  41. break;
  42. }
  43. }
  44. }
  45. void notify(string message) override {
  46. // 通知所有观察者
  47. for (Observer* observer : observers) {
  48. observer->update(message);
  49. }
  50. }
  51. };
  52. // 测试
  53. int main() {
  54. // 创建公众号
  55. WeChatOfficialAccount account;
  56. // 创建订阅者
  57. Observer* sub1 = new Subscriber("张三");
  58. Observer* sub2 = new Subscriber("李四");
  59. Observer* sub3 = new Subscriber("王五");
  60. // 订阅公众号
  61. account.attach(sub1);
  62. account.attach(sub2);
  63. account.attach(sub3);
  64. // 公众号发送消息
  65. account.notify("C++全体系博客更新啦!");
  66. // 李四取消订阅
  67. account.detach(sub2);
  68. account.notify("新增设计模式实战案例~");
  69. // 释放内存
  70. delete sub1;
  71. delete sub2;
  72. delete sub3;
  73. return 0;
  74. }
复制代码

四、C++实战技巧与避坑指南

1. 实战技巧

  • 代码规范:命名规范(类名首字母大写,函数/变量名小写,用下划线分隔)、注释规范(关键代码添加注释,说明功能和逻辑)、代码缩进(统一缩进格式,提升可读性)。

  • 性能优化:尽量使用引用/指针传递参数(避免拷贝开销)、优先使用栈内存(栈内存分配释放比堆内存快)、合理使用智能指针(避免内存泄漏)、减少全局变量的使用(全局变量生命周期长,占用内存)。

  • 调试技巧:使用cout打印调试信息、使用调试工具(VS的调试器、GDB)、添加日志输出(记录程序运行状态和错误信息)。

  • 兼容性:注意C++版本兼容性(比如C++11的特性在旧编译器中可能不支持)、避免使用平台相关的API(提升代码可移植性)。

2. 常见坑点与避坑指南

  • 内存泄漏:避免忘记释放new分配的内存,优先使用智能指针;避免循环引用(shared_ptr的循环引用,用weak_ptr解决)。

  • 野指针:指针使用前必须初始化,避免使用已释放的指针;函数返回局部变量的指针/引用(局部变量生命周期结束后会被释放,指针/引用变为野指针)。

  • 多态使用错误:父类析构函数未设为虚函数(子类对象析构不彻底,导致内存泄漏);重写虚函数时签名不一致(无法实现动态多态)。

  • STL容器使用错误:vector的迭代器失效(比如插入/删除元素后,迭代器可能失效,需重新获取);map的键不可修改(map的键是const类型)。

  • const使用错误:const修饰的变量被修改;const成员函数中修改成员变量(需加mutable关键字)。

五、学习路径与后续更新计划

1. 推荐学习路径

C++学习循序渐进,建议按以下路径学习,避免跳跃式学习:

  1. 基础阶段:语法基础(变量、函数、条件循环)→ 面向对象三大支柱(封装、继承、多态)→ 动态内存分配;

  2. 进阶阶段:智能指针 → STL容器与算法 → 异常处理 → lambda表达式 → 模板;

  3. 设计模式阶段:先掌握高频模式(单例、工厂、策略、观察者)→ 再学习其他模式 → 结合实战案例灵活运用;

  4. 实战阶段:编写小demo(比如简单的控制台程序)→ 参与小型项目 → 优化代码(运用设计模式、性能优化技巧)。

2. 后续更新内容

这篇博客会持续更新,后续会补充以下内容,大家可以关注收藏:

  • C++进阶补充:右值引用、移动语义、模板进阶、多线程编程;

  • 更多设计模式实战:结合具体工程场景,讲解如何组合使用多种设计模式;

  • C++面试高频考点:基础语法、进阶知识点、设计模式的面试题解析;

  • 实战项目:从零搭建一个C++小项目(比如日志系统、简单的计算器),覆盖所学知识点。

3. 学习建议

很多同学学习C++和设计模式时,容易陷入“只看不动手”的误区,这里给大家两个关键建议:

  • 基础部分:多敲代码,每一个语法点、每一个特性,都亲手写示例验证,比如指针和引用的区别、多态的实现,只有亲手敲过,才能真正理解;

  • 设计模式:不要死记硬背,重点理解“为什么要用这种模式”“适用场景是什么”,然后尝试用代码实现,再结合实际项目(哪怕是小demo),思考如何运用这些模式优化代码。

最后,C++的学习是一个循序渐进的过程,基础扎实了,设计模式才能融会贯通;设计模式掌握了,代码质量才能上一个台阶。C++没有“速成”的方法,唯有多敲、多练、多思考,才能真正掌握这门语言。后续每更新一部分,我都会同步补充示例代码和实战技巧,大家有任何疑问、建议,都可以在评论区留言,咱们一起交流、一起进步~

下一篇:C++ STL容器详解(vector、map、string高频使用场景+实战技巧),敬请期待!

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

中国红客联盟公众号

联系站长QQ:5520533

admin@chnhonker.com
Copyright © 2001-2026 Discuz Team. Powered by Discuz! X3.5 ( 粤ICP备13060014号 )|天天打卡 本站已运行