C++ 运算符重载:让自己的类也能用 +、==、<<
运算符重载(operator overloading)就是给自定义类型(类 / 结构体)定义运算符的行为。默认情况下,int a + int b 这种内置类型能 +,但 MyClass a + MyClass b 编译器不知道怎么办——除非你告诉它「+ 在我的类上应该怎么算」。 一、为什么需要运算符重载举一个简单的例子:复数类想实现两个复数相加: 123struct Complex { double real, imag;}; 如果直接写 c1 + c2,编译报错:no match for 'operator+' ...。 通过运算符重载,可以写成像内置类型一样自然: 1Complex c3 = c1 + c2; // 像 int 那样用 二、运算符重载的语法两种形式: 形式 1:成员函数123456struct Complex { double real, imag; Complex operator+(const Complex& other) const { retur...
C++ 多线程:从「一前一后」到「一起跑」
头文件:<thread> 线程(thread)是操作系统调度的最小单位——一个进程里的多个线程共享同一块内存,轮流被 CPU 执行。多线程适合"互不相关的任务一起跑"(如一边下载一边显示进度),但共享数据需要保护。 一、第一个线程程序123456789101112131415#include <iostream>#include <thread>#include <string>using namespace std;void print(string msg) { cout << msg << endl;}int main() { // 创建线程,把参数传给线程入口函数 thread t(print, "Hello, thread!"); t.join(); // 主线程等待 t 线程结束 return 0;} join() 之后 t 就不能再次 join/detach 了。 二、线程...
C++ 右值引用与移动语义
核心解决的痛点:大对象拷贝时产生昂贵的深拷贝开销,浪费内存、时间。例如 vector<string>、自定义的大数组对象,拷贝会复制全部数据;移动语义可以直接"偷走"资源,不复制数据。 一、左值、右值 venn A(glvalue):::yellow B(rvalue):::green A only A: lvalue A intersect B: xvalue B only B: prvalue classDef yellow fill:#f2d249,stroke:#cc9900 classDef green fill:#309955,stroke:#106633 左值(lvalue)能取地址、可以修改的持久对象,有名字。 12int a = 10; // a 是左值int b = a; // a 作为表达式结果是右值,但 a 这个变量本身是左值 可以写 &a 取地址。 右值(rvalue)临时对象,没有名字,不能取地址,生命周...
C++ 智能指针:用 RAII 让堆内存"自动归还"
头文件:#include <memory> 智能指针的核心目的:自动管理堆内存,离开作用域自动释放,杜绝内存泄漏。底层原理:RAII(Resource Acquisition Is Initialization,资源获取即初始化)——构造时拿到资源,析构时释放资源。 裸指针的痛点:new 出来的内存忘 delete → 内存泄漏;重复 delete;野指针。智能指针把 delete 写进了析构函数。 一、三大智能指针总览 类型 所有权模型 拷贝 底层开销 用途 unique_ptr 独占 ❌ 不可拷贝,只能 move 极小(≈裸指针) 绝大多数场景首选 shared_ptr 共享(引用计数) ✅ 原子计数,开销大 需要多个指针共用一块内存 weak_ptr 弱引用,不拥有 ✅ 很小 配合 shared_ptr 解决循环引用 二、unique_ptr:独占智能指针一块堆内存,只能有一个 unique_ptr 指向它:不能拷贝,只能移动。 123456789101112131415161718192021222324252627#incl...
C++ Lambda 表达式(匿名函数):写临时小函数的「快捷方式」
Lambda 表达式就是一个当场写、当场用、不用起名字的小函数。在 sort、for_each、STL 容器遍历里写回调非常方便,比单独写全局函数或仿函数更紧凑。 一、完整语法1[捕获列表](参数列表) mutable -> 返回值类型 { 函数体 }; 拆成 5 部分: 位置 名称 说明 [] 捕获列表 把外面变量抓到 lambda 内部使用(最核心、最容易踩坑) () 参数列表 和普通函数参数一样 mutable 可选 允许修改「值捕获」的副本 -> 类型 尾置返回类型 可选,大部分情况编译器能自动推导 {} 函数体 真正执行的代码 大括号后面的分号 ; 不要漏——lambda 整体是一个表达式,表达式必须以分号结尾。 二、捕获列表(最核心、最容易踩坑) 写法 含义 [] 不捕获任何外部变量 [=] 值捕获:复制一份进 lambda,只读;加 mutable 才能改副本,但不会改原值 [&] 引用捕获:全部变量引用,lambda 内修改会直接改动原值 [x] 只值捕获...
原码、反码、补码:为什么计算机只用「加法」就能做减法
计算机里的加法器只懂 +,但我们又必须能做减法。原码、反码、补码就是为这个问题设计的三层「表示同一数字的不同方式」。这一篇从问题出发,把它们的来历、关系和实际计算流程串清楚。 一、计算机怎么表示一个数字1. 二进制位与「符号位」假设我们用 8 位二进制表示一个整数。最高位(第 7 位)当作「符号位」: 0 = 正数 1 = 负数 剩下的 7 位存「数值部分」(按二进制位权)。 举例: 十进制 二进制(8 位) 含义 +14 0 0001110 符号位 0(正),数值 0001110 = 14 −21 1 0010101 符号位 1(负),数值 0010101 = 21 为什么符号位只能放最前面? 因为它不参与位权计算,把它放最左/最右都行,统一约定放最左(最高位)方便电路判断正负。 1.1 8 位能表示的范围 编码方式 最小值 最大值 个数 无符号 0 255 256 有符号(任一编码) −128 +127 256 无论用哪种编码,256 个编码对应 256 个数字,总数不变。 二、三种编码设正数 $x$ 的二进制绝对...
进制转换:从二进制、八进制、十六进制到十进制的速算
这一篇把「二进制、八进制、十进制、十六进制」之间的相互转换整理成一份速查表,每一种都配一个具体例子的手工计算步骤。 记号约定: 数字后缀 (B)=二进制、(O)=八进制、(D)=十进制、(H)=十六进制 十六进制字母 (\text{A}=10)、(\text{B}=11)、(\text{C}=12)、(\text{D}=13)、(\text{E}=14)、(\text{F}=15) 一、四个核心概念1. 基数进制就是「每一位上能用几个数字」。每进一位就乘一次基数 (r): 进制 基数 (r) 数字范围 二进制 (B) 2 0, 1 八进制 (O) 8 0 ~ 7 十进制 (D) 10 0 ~ 9 十六进制 (H) 16 0 ~ F 2. 位权第 (i) 位(从右往左,从 (0) 开始数)的权值是 (r^i)。例如二进制 10110(5 位)的位权依次是 (2^4, 2^3, 2^2, 2^1, 2^0): 123位号: 4 3 2 1 0数字: 1 0 1 1 0位权: 16 8 4 2 1 3. 按权展开(任意进制 → 十进制的通用公...
STM32 入门笔记 04:旋转编码器与双 EXTI 中断
这是 STM32 入门笔记专栏的第 04 篇。在会了 EXTI 之后,再用它做点「有意思」的事——旋转编码器:拧一下旋钮,单片机就能分辨出是「顺时针」还是「逆时针」转了一格。 一、什么是旋转编码器旋转编码器是一种「拧一格、输出两相脉冲」的机电元件,常见的是 EC11 系列(淘宝几块钱一只)。它有 3 个引脚:A 相、B 相、GND(有的型号中间还多一个 C 接 VCC,按键按下才接通的「中心轴按下」功能)。 波形长相(理想情况下): 12A 相: _____|‾‾‾‾|_____ 上升 → 下降B 相: __|‾‾‾‾|_____ 在 A 之前就上升 旋转方向不同,A、B 相谁先变化也不同: 旋转方向 A 边沿时 B 的状态 顺时针 A 上升时 B = 0;A 下降时 B = 1 逆时针 A 上升时 B = 1;A 下降时 B = 0 推论:只要在 A 的某个边沿(比如下降沿)触发中断,进去读 B 现在的电平,就能判断方向。 二、接线约定 A 相 → PA0(EXTI0,独立 IRQ,方便调试) B 相 → PB0(EXTI0...
STM32 入门笔记 03:EXTI 外部中断——原理 + 对射式红外计次
这是 STM32 入门笔记专栏的第 03 篇。在能按键检测之后,轮询 (while(!key)) 已经不够用了——本篇引入中断机制,让 CPU 在按键被按下时才被「打断」去处理,其它时间可以睡觉、做别的事。 一、为什么需要中断想象你守在门口等快递: 轮询(poll):每秒钟起来看一眼门口有没有快递——你啥也别干了; 中断:坐下来睡觉,快递小哥敲门时再起床——绝大多数时间都在做自己的事。 单片机里也是一样的: 轮询:CPU 不断读按键引脚电平,99% 时间都是浪费的; 中断:CPU 跑主循环,按键变化时硬件自动打断 CPU,让它先跑中断函数,处理完再回来。 STM32 的中断系统分为两层: 缩写 全称 作用 NVIC Nested Vectored Interrupt Controller 内核里的「中断总管家」,负责优先级分组、嵌套、使能 EXTI External Interrupt 把 GPIO 引脚的电平变化转成「中断事件」 二、NVIC 的优先级分组STM32 把优先级分成两类: 名称 作用 类比 抢占优先级 决定「...
STM32 入门笔记 02:OLED 显示屏与硬件接线注意
这是 STM32 入门笔记专栏的第 02 篇。在能点亮 LED 之后,下一步通常是把 OLED 显示屏接上,单片机把数据 / 文字显示出来,能让调试过程直观得多。 一、OLED 是什么OLED(Organic Light-Emitting Diode,有机发光二极管)是一种自发光显示技术,每个像素都能自己发光,不需要背光。在嵌入式领域常见的是 0.96 寸 128×64 单色 OLED 屏,通常用 SSD1306 这颗驱动芯片,支持 I²C 或 SPI 两种通信接口(看型号后缀,4 针的几乎都是 I²C)。 特点: 薄、轻、功耗低——适合手持 / 可穿戴设备; 对比度高——黑的真黑,亮字清晰; 每个像素独立发光——理论上响应时间比 LCD 快; 寿命有限——蓝色像素老化得最快,长时间高亮度全亮会烧屏; 接口简单——4 根线(VCC / GND / SCL / SDA)就能用 I²C 驱动。 二、4 针 I²C OLED 的引脚定义江科大最小系统板上常见的是 0.96 寸 4 针 I²C 模块,引脚定义如下: 引脚 名称 说明 VCC 电源 接 3.3V(绝...