- 博客(120)
- 收藏
- 关注
原创 关联式容器:map 与 multimap 的键值对存储
map(映射):存储唯一关键字(key)的键值对,自动按关键字升序(默认)排序,不允许重复key。若插入重复key,会被自动忽略,不会报错;每个key唯一对应一个value,实现“一对一”映射。multimap(多重映射):存储可重复关键字(key)的键值对,自动按关键字升序(默认)排序,允许重复key。若插入重复key,会全部保留,且按排序规则插入到对应位置,维持整体有序;一个key可对应多个value,实现“一对多”映射。
2026-02-18 23:54:54
771
原创 关联式容器:set 与 multiset 的有序存储
set(集合):存储唯一关键字(元素),自动按关键字升序(默认)排序,不允许重复元素。插入重复元素时,会被自动忽略,不会报错。multiset(多重集合):存储可重复关键字(元素),自动按关键字升序(默认)排序,允许重复元素。插入重复元素时,会全部保留,且按排序规则插入到对应位置,维持整体有序。两者都有序,唯一区别是set去重,multiset允许重复。
2026-02-18 23:52:13
749
原创 序列式容器:deque 双端队列的适用场景
双端操作+随机访,deque优先上;仅需随机用vector,中间操作选list;内存受限慎选择,按需匹配不慌张。再补充3个实战小贴士,帮你更精准使用deque:deque的迭代器是随机访问迭代器,支持++、–、+n、-n操作,用法和vector的迭代器一致,可直接用于STL算法(如sort、find);deque没有capacity(容量)概念(分段内存,无需预留容量),只有size(大小),resize()函数可调整元素个数,用法和vector一致;
2026-02-17 17:39:55
919
原创 序列式容器:list 双向链表的特性与用法
list 虽然不支持随机访问,但依然可以与 STL 算法协同使用,同时也支持存储自定义类型,实现排序、去重等高级操作。需要注意的是,list 有自己的成员函数 sort(),效率比 STL 通用算法 sort() 更高。list 支持存储任意自定义类型(结构体、类),用法与 vector 类似,只需确保自定义类型有默认构造函数(如果手动定义了带参构造,需显式定义默认构造),同时可以自定义排序规则,适配 list 的 sort() 函数。// 自定义结构体:学生信息int age;int score。
2026-02-17 17:37:50
1040
原创 STL 容器:vector 动态数组的全面解析
vector 不仅支持内置类型,还支持自定义结构体、类,同时可以与STL算法协同使用,实现排序、去重等高级操作,这也是vector高频使用的场景之一。存储自定义结构体时,需确保结构体有默认构造函数(如果手动定义了带参构造,需显式定义默认构造),否则初始化时会报错。// 自定义结构体:学生信息int age;int score;// 默认构造函数(必须有,否则vector<Student> v(5)会报错)// 带参构造函数(方便初始化)// 初始化自定义结构体vector。
2026-02-16 22:12:25
1053
原创 标准模板库 STL:C++ 的利器 —— 容器、算法、迭代器
看到这里,相信你已经对容器、算法、迭代器有了基本的了解,接下来我们用一句话总结它们的协同逻辑:容器存储数据,迭代器作为容器的“访问接口”,算法通过迭代器获取容器中的元素,完成对数据的处理——三者相互独立又相互依赖,构成了STL的核心。举个生活中的例子:容器就像一个“冰箱”(存放食物/数据),迭代器就像“冰箱门的把手”(通过把手访问冰箱里的食物),算法就像“烹饪工具”(通过把手拿出食物,用工具处理食物)。
2026-02-16 22:10:00
1475
原创 异常规范与自定义异常类的设计
异常规范,简单来说,就是对函数可能抛出的异常类型进行明确声明,告诉调用者“这个函数只会抛出这些类型的异常,其他类型的异常不会从这里抛出”。为什么需要异常规范?举个例子:如果一个函数没有任何异常声明,调用者无法提前预知它会抛出什么异常,只能用 catch (…) 万能捕获,既不规范,也不利于排查错误;而有了异常规范,调用者可以精准捕获对应类型的异常,代码的可读性和可维护性会大大提升。
2026-02-15 22:47:46
839
原创 C++ 异常处理:try-catch-throw 的基本用法
其实 try-catch-throw 的核心逻辑很简单:用 try 监控风险代码,用 throw 抛出异常警报,用 catch 捕获并处理警报。掌握了今天讲的基本用法,就能应对大部分简单的异常场景。后续我们还可以聊聊更高级的用法,比如自定义异常类、异常的传递、noexcept 关键字等。最后,建议大家把上面的示例代码复制到编译器中运行一遍,亲手测试不同的输入,感受异常处理的流程——实践比死记语法更重要哦~
2026-02-15 22:45:11
686
原创 模板参数:类型参数与非类型参数的区别
模板参数,简单来说,就是「模板被实例化时,需要传入的“参数”」——类比函数参数:函数参数是运行时传入具体值,模板参数是编译期传入具体“内容”,让编译器根据传入的参数,生成对应版本的代码。根据传入“内容”的不同,模板参数分为两大类:类型参数:传入的是「数据类型」(如int、double、std::string、自定义结构体);非类型参数:传入的是「常量值」(如10、3.14、nullptr、常量表达式)。
2026-02-14 22:04:38
1005
原创 模板特化:为特定类型定制模板实现
模板特化的本质,是「泛型与定制的平衡」——它让我们既能享受泛型编程带来的代码复用,又能应对特殊类型的个性化需求,避免“一刀切”的实现带来的冗余和问题。记住三个核心点,就能灵活使用模板特化:全特化:所有参数都确定,针对单一类型组合定制;偏特化:部分参数确定,针对一类参数组合定制(仅类模板支持);优先级:特化版本优先于通用版本,编译器自动匹配最适合的实现。
2026-02-14 22:00:52
792
原创 类模板:实现通用数据结构的基础
类模板的核心思想是“用占位符表示类中使用的数据类型”,其语法与函数模板相似,但有两个关键区别:1. 模板声明需紧跟在类定义之前;2. 类模板实例化时,必须显式指定类型(无法像函数模板那样自动推导)。模板声明(Template Declaration)和类定义(Class Definition),语法简洁且固定,初学者只需牢记模板声明的位置和实例化的要求即可。当类模板的成员函数较长时,推荐在类模板外部定义(提高代码可读性),此时需注意两个关键细节:1. 外部定义前必须再次添加模板声明;
2026-02-13 21:31:28
883
原创 C++ 模板入门:函数模板的定义与使用
函数模板的核心思想是“泛型”——脱离具体数据类型,实现通用逻辑。模板声明(Template Declaration)和函数定义(Function Definition),语法简洁且固定,初学者只需牢记模板声明的格式和占位符的使用即可。// 错误:模板声明与函数模板定义之间,插入了其他代码(cout语句)cout << "模板声明" << endl;// 错误:中间不能有其他代码// 正确:模板声明紧跟函数模板定义,中间无任何代码int x;int y;
2026-02-13 21:17:12
1295
原创 虚基类:解决多重继承中的二义性问题
虚基类是C++多重继承中“解决二义性和内存冗余”的核心技术,其核心价值是“确保顶层基类在最终子类中只保留一份拷贝”,尤其适用于菱形继承场景。掌握它的语法、使用场景和常见误区,能帮你写出更健壮、更高效的多重继承代码,同时应对笔试、面试中的高频考点。解决菱形继承(多路径继承同一基类)中的二义性和内存冗余问题,确保顶层基类在最终子类中只保留一份拷贝。语法格式:virtual关键字加在“中间父类→顶层基类”的继承关系中(如),顶层基类和最终子类无需加virtual。构造顺序:使用虚基类后,
2026-02-12 23:09:20
874
原创 虚析构函数:解决子类对象的内存泄漏
虚析构函数是C++多态开发中“内存安全”的关键,其核心价值是“解决子类对象的内存泄漏”,本质是“让析构函数支持动态绑定”。掌握它的使用场景、语法规则和常见误区,能帮你写出更健壮、更安全的面向对象代码,同时应对笔试、面试中的高频考点。
2026-02-12 22:46:34
670
原创 纯虚函数与抽象类:定义接口规范
包含纯虚函数的类,称为抽象类抽象类的本质是“接口类”,它只负责定义接口规范,不负责提供具体实现,也不能实例化对象——它的唯一用途,是作为父类被子类继承,让子类实现其定义的接口。补充说明:抽象类可以包含普通成员变量、普通成员函数(非虚函数)、普通虚函数,只要包含至少一个纯虚函数,它就是抽象类。抽象类的核心价值的是“定义接口规范”,在实际开发中,凡是需要“统一接口、多实现”的场景,都可以用抽象类。下面我们结合两个高频实战场景,演示抽象类的实际应用,帮你掌握“接口设计”的思路。
2026-02-11 12:14:10
388
原创 多态性:虚函数与动态多态的实现原理
静态多态和动态多态。其中,动态多态是面向对象编程的核心,也是我们本文的重点,而静态多态则是更基础的“编译期绑定”机制。多态(Polymorphism):同一操作作用于不同类型的对象,会产生不同的执行结果。简单来说,就是“调用同一个方法名,不同对象会做不同的事情”。通俗示例:“吃饭”这个操作,中国人对象执行“吃米饭”,美国人对象执行“吃面包”,狗对象执行“吃狗粮”——“吃饭”是同一个接口,不同对象有不同的实现,这就是多态。
2026-02-11 12:10:24
380
原创 函数重写:子类对父类方法的覆盖
函数重写是C++面向对象编程中实现“个性化复用”的核心机制,也是后续学习多态的基础,掌握其核心要点,能帮你写出更灵活、更规范的继承体系代码,同时规避笔试中的高频陷阱。函数重写的本质,是“在继承的基础上,保留父类方法的接口,修改其实现”,既保证了代码的复用性,又实现了子类的个性化需求。在实际开发中,只要遇到“子类需要修改父类方法行为”的场景,就可以使用函数重写——比如不同子类对父类通用方法的个性化改造、框架中对基类方法的扩展等。
2026-02-10 18:29:02
334
原创 继承方式:public、private 与 protected 继承
继承的本质不变:无论哪种继承方式,子类都会继承父类的所有成员(包括private成员),区别仅在于“继承后成员的访问权限”;父类private成员的特殊性:无论哪种继承方式,父类的private成员子类都无法直接访问,仅能通过父类提供的public/protected接口间接访问;权限变化规律:public继承“权限不变”,protected继承“public→protected,protected不变”,private继承“public、protected→private”;
2026-02-10 18:25:04
759
原创 C++ 继承:子类与父类的继承关系
在C++面向对象编程中,我们已经学习了类的基本结构、构造函数、析构函数、this指针、静态成员,以及友元函数与友元类。上一篇博客中我们重点强调:友元机制可以突破类的访问权限限制,允许指定的外部函数、其他类直接访问当前类的私有成员,但其核心是“补充封装”而非“否定封装”,且友元关系具有单向性、无传递性、不可继承的特点。
2026-02-09 13:39:22
1215
原创 友元函数与友元类:突破访问权限的限制
在不滥用的前提下,突破C++类的访问权限限制,允许指定的外部函数、其他类直接访问当前类的私有成员,从而简化代码、提升效率——它是C++封装特性的“补充”,而不是“否定”,核心作用是解决“类与类、函数与类之间紧密协作”的场景需求。友元分为友元函数和友元类,核心作用是突破访问权限限制,直接访问当前类的所有成员;友元函数不是类的成员函数,无this指针,访问成员需通过对象参数;友元类的所有成员函数,都能直接访问当前类的所有成员,友元关系是单向、无传递性的;
2026-02-09 11:30:33
994
原创 this 指针:指向对象自身的隐含指针
this指针(this pointer),是C++编译器自动隐含在所有非静态成员函数指向当前正在调用该非静态成员函数的对象,即“对象自身的指针”。我们可以把this指针理解为:每个非静态成员函数都有一个“隐藏的第一个参数”,这个参数就是this指针,它由编译器自动传递,不需要我们手动声明、也不需要我们手动传递——我们看不见它,但它一直存在,默默发挥作用。this指针的核心是“隐含在非静态成员函数中的、指向当前对象的常量指针”——它看不见、摸不着,但无处不在,是连接非静态成员函数与对象自身的“桥梁”。
2026-02-08 11:21:34
804
原创 静态成员函数:没有 this 指针的特殊函数
静态成员函数(Static Member Function),是被static关键字修饰没有this指针。正因为没有this指针,静态成员函数与“对象”解绑——无需创建任何对象,就能直接通过类名调用;同时,也正因为没有this指针,它无法访问“属于对象的成员”(非静态成员变量、非静态成员函数),只能访问“属于类的成员”(静态成员变量、其他静态成员函数)。静态成员函数的核心是“没有this指针”,这一特性决定了它的所有使用规则:不依赖对象、能直接通过类名调用、只能访问静态成员、不能实现多态。
2026-02-08 11:16:18
974
原创 静态成员变量:属于类的共享变量
静态成员变量(Static Member Variable),是被static关键字修饰不属于类的任何一个具体对象,而是属于整个类,被所有类对象共享。我们可以用一个形象的比喻理解:类就像一个“模板”,静态成员变量就像模板上的“公共标记”,所有根据这个模板创建的对象,都能看到、访问这个公共标记,并且修改这个标记会影响所有对象;而非静态成员变量,就像模板上的“私人字段”,每个对象创建时,都会给私人字段填充独立的值,互不影响。静态成员变量的核心是“属于类、共享于所有对象。
2026-02-07 12:11:12
344
原创 深拷贝与浅拷贝:解决指针成员的拷贝问题
浅拷贝,对于指针成员而言,仅复制指针变量本身的值(即堆区内存地址),不复制指针指向的堆区数据,也不重新分配堆区内存。拷贝后,原对象和新对象的指针成员,指向同一块堆区内存,共用同一份数据资源。深拷贝,对于指针成员而言,不仅复制指针变量本身的值,还会为新对象的指针成员重新分配一块独立的堆区内存,并将原对象指针指向的堆区数据,逐一复制到新分配的堆区内存中。拷贝后,原对象和新对象的指针成员,指向不同的堆区内存,拥有独立的数据资源,互不影响。
2026-02-07 12:00:11
353
原创 拷贝构造函数:对象复制的底层原理
拷贝构造函数,是构造函数的一种特殊重载形式用一个已存在的同类对象,初始化一个新的同类对象,确保新对象的成员变量与原对象完全一致(默认行为)。class 类名 {public:// 拷贝构造函数(唯一正确格式)类名(const 类名& 原对象引用) {// 函数体:将原对象的成员变量赋值给新对象新对象成员变量 = 原对象引用.成员变量;关键语法细节(必记,底层调用的基础):函数名称:与类名完全一致(遵循构造函数的基本要求);无返回值:与所有构造函数一致,不能写返回值类型(包括void);
2026-02-06 11:58:29
332
原创 构造函数重载:多种方式初始化对象
在同一个类中,定义多个名称与类名完全一致无返回值,但参数列表不同的构造函数,称为构造函数重载。这里的“参数列表不同”,包含三种情况(满足任意一种即可):参数个数不同(比如一个无参,一个有1个参数,一个有2个参数);参数类型不同(比如两个构造函数,一个参数是int,一个参数是double);参数顺序不同(比如两个构造函数,参数分别是“int, string”和“string, int”)。
2026-02-06 11:48:00
277
原创 析构函数:对象销毁时的清理工作
析构函数(Destructor)是类的特殊成员函数,它的名称是波浪号(~)+ 类名,没有返回值(和构造函数一样,不是void,是完全没有返回值),没有参数,不能重载,当对象销毁时,编译器会自动调用析构函数,仅用于清理对象占用的资源(如堆区内存、文件、网络连接等)。private:// 学号(栈区成员,自动销毁)// 姓名(栈区成员,自动销毁)// 成绩指针(指向堆区内存,需手动释放)public:// 构造函数:初始化成员变量,给m_score分配堆区内存m_id = id;
2026-02-05 13:07:01
629
原创 构造函数:初始化对象的特殊成员函数
构造函数(Constructor)是类的特殊成员函数,它的名称和类名完全一致,没有返回值(注意:不是void,是完全没有返回值,包括return语句也无需写),不需要手动调用,创建对象时自动调用,仅用于初始化对象的成员变量。private:// 学号// 姓名// 成绩public:// 手动定义构造函数(无参构造)// 名称与类名一致,无返回值,无参数// 初始化成员变量(避免随机值)m_id = "";// 学号初始化为空字符串m_name = "未知";// 姓名初始化为“未知”
2026-02-05 12:19:44
1005
原创 类的访问权限:public、private 与 protected 详解
private修饰的类成员(成员变量、成员函数),仅能在当前类的内部被访问,类外部(包括通过对象访问)、子类内部均无法直接访问。✅ 类内部:可访问(成员函数可直接操作private成员变量、调用private成员函数);❌ 类外部:不可访问(无法通过对象直接访问private成员,编译报错);❌ 子类内部:不可访问(子类无法直接访问父类的private成员)。public修饰的类成员(成员变量、成员函数),可在类内部、类外部、子类内部均能被访问,没有访问限制。✅ 类内部:可访问;
2026-02-04 11:23:15
1192
原创 C++ 类与对象:类的定义与对象的创建
类是抽象的、概念性的,它不代表具体的事物,只是一个“模板”,用于定义某一类事物共有的“属性”(数据)和“行为”(操作数据的方法)。通俗类比:“学生”类:定义了所有学生共有的属性(学号、姓名、年龄、成绩),共有的行为(上课、考试、提交作业);“手机”类:定义了所有手机共有的属性(品牌、型号、价格、内存),共有的行为(打电话、发消息、拍照)。类的核心作用:封装——将属性和行为打包在一起,隐藏内部细节,只暴露外部可访问的接口(方法),这正是面向对象思想的核心体现。
2026-02-04 11:13:02
1563
原创 面向对象思想:从面向过程到面向对象的转变
面向过程(Procedural Programming,简称PP),是最贴近人类“做事习惯”的编程思想,也是大多数初学者入门编程时接触的第一种思想——比如我们学习C语言时,写的每一个程序,本质上都是面向过程的。面向对象(Object-Oriented Programming,简称OOP),是为了解决面向过程的局限而诞生的编程思想——它不聚焦“步骤”,而是聚焦“参与者”,将“数据”和“操作数据的方法”封装在一起,通过“参与者”的交互完成任务。
2026-02-03 12:12:41
2077
原创 格式化输入输出:控制输出精度与对齐方式
格式化输入输出是C++输入输出流的进阶用法,核心价值是“让输入更灵活、输出更规范、更美观”,本文重点聚焦日常开发中最常用的输出精度控制和输出对齐控制,补充少量高频格式化输入场景,衔接前文cin、cout基础用法和using关键字知识点,形成完整的输入输出知识体系。
2026-02-03 12:09:23
1071
原创 C++ 输入输出流:cin 与 cout 的基础用法
在C++中,输入输出(I/O)的本质是“数据的流动”,类比生活中的“水流”,我们可以更直观地理解:输出流(cout):数据从程序“流向”屏幕(或其他输出设备),相当于程序向屏幕“打印”信息,是我们查看程序运行结果的主要方式;输入流(cin):数据从键盘(或其他输入设备)“流向”程序,相当于用户向程序“传递”信息,让程序可以根据用户输入执行不同的逻辑。关键补充:C++标准库为我们提供了现成的输入输出工具,无需我们自己实现底层逻辑——cout是“character output”的缩写,专门用于标准输出。
2026-02-02 10:59:47
782
原创 using 关键字:命名空间的使用与注意事项
前文我们学习了typedef关键字,用于为已有的类型创建别名(如),而C++11引入了using的新用法——用using定义类型别名,语法更直观、更灵活,尤其适合复杂类型(如函数指针、模板类型),功能与typedef完全等价。using 别名 = 原类型;对比typedef,优势明显:语法顺序更直观(先写别名,再写原类型),支持模板别名,可读性更强。// 1. 基础类型别名(对比typedef)// typedef写法:原类型在前,别名在后// using写法:别名在前,原类型在后(更直观)
2026-02-02 10:55:02
441
原创 命名空间 namespace:解决命名冲突的利器
命名空间(namespace)是C++中的一种语法结构,用于划分标识符的作用域,将一组相关的变量、函数、类、结构体、枚举类等标识符封装在一个独立的“命名域”中。不同命名空间中的同名标识符互不干扰,从而解决命名冲突问题。关键补充:命名空间与前文学习的“作用域”密切相关,但又不同于局部作用域、全局作用域——命名空间可以自定义作用域范围,支持嵌套、合并,灵活性更强,是专门为解决“全局命名冲突”设计的。
2026-02-01 11:58:34
682
原创 宏定义与 const 常量:哪个更适合 C++ 开发?
首先明确两个核心前提:宏定义属于预处理指令,const常量属于C++语言的核心语法;宏定义发生在预处理阶段,const常量发生在编译阶段,二者的执行时机完全不同,这也是后续所有差异的根源。宏定义是通过#include、#define等预处理指令实现的,核心作用是“将宏名与一段文本绑定”,在预处理阶段,预处理器会将所有出现该宏名的地方,统一替换为对应的文本——无类型检查、不占用内存、仅做文本替换。// 宏定义常量(无类型、无分号、纯文本替换)#define PI3.1415926// 数值常量。
2026-02-01 11:55:11
541
原创 C++ 预处理指令:#include、#define 与条件编译
文本替换(如宏替换、文件包含)、条件筛选(如保留符合条件的代码、删除不符合条件的代码)、注释删除(将//和//注释替换为空)。预处理的输出是“预处理后的源代码”,该代码不再包含任何预处理指令,仅保留纯C++语法代码,供编译器后续处理。语法格式:#include “头文件名.h”适用场景:引入自己编写的头文件(如自定义的结构体、函数声明、宏定义等,通常以.h为后缀),预处理器会先到当前源文件所在的目录中查找头文件,若找不到,再到系统标准库路径中查找。
2026-01-31 11:41:42
836
原创 类型别名 typedef:让复杂类型更简洁
typedef(type definition,类型定义)是C++中的关键字,用于为已存在的类型(无论是基础类型、聚合类型,还是复杂的指针、函数类型)创建一个新的“别名”。注意:typedef不会创建新类型,只是为原有类型起一个更简洁、更贴合场景的名字,原类型和别名完全等价,可互换使用。举个最简单的例子:C++中的unsigned int类型,书写起来略显繁琐,我们可以用typedef为其创建别名UInt,后续使用UInt就等同于使用unsigned int。
2026-01-31 11:38:46
1110
原创 函数占位参数:语法规则与实际应用场景
函数占位参数,是指在函数声明或定义时,只指定参数的数据类型,不给出参数名的参数。这类参数在函数体内部无法直接使用(因为没有参数名可供引用),其核心作用不在于“传递数据”,而在于“占据参数位置”,用于匹配函数调用、区分重载函数或预留接口。函数占位参数是C++中一种“特殊且实用”的参数形式,核心价值不在于传递数据,而在于“占据参数位置、区分重载函数、实现版本兼容、预留接口”。它的语法简洁(仅声明类型,无参数名),但使用有严格规则——普通参数在前、占位参数在后,可与默认参数结合,且无法在函数体中使用。
2026-01-30 11:58:33
835
原创 函数默认参数:C++ 中参数默认值的设置规则
函数默认参数,是指在函数声明或定义时,通过“参数名 = 默认值”的语法,为函数的一个或多个参数指定固定值。调用该函数时,有两种选择:传入该参数:编译器使用传入的值执行函数;不传入该参数:编译器自动使用预先指定的默认值执行函数。函数的默认参数只需在“声明”或“定义”中设置一次即可,若同时在声明和定义中设置默认值(即使默认值相同),会导致编译错误。默认参数优先在函数声明中设置(尤其是多文件项目中),函数定义中无需重复设置——这样既能保证所有调用处都能看到默认参数,又能避免重复设置的错误。
2026-01-30 11:37:43
748
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅