【第52节】Windows编程必学之从零手写C++调试器下篇(仿ollydbg)
目录
一、引言
二、调试器核心功能设计与实现
三、断点功能
四、高级功能
五、附加功能
六、开发环境与实现概要
七、项目展示及完整代码参考
八、总结
一、引言
在软件开发领域,调试器是开发者不可或缺的工具。它不仅能帮助定位代码中的逻辑错误,还能深入理解程序运行时的底层机制。本文将阐述一个基于Windows 10操作系统和VS2015开发环境、使用C/C++语言实现的调试器项目。该调试器具备丰富的基础功能、断点机制、高级特性及附加工具,项目旨在熟悉调试器开发原理,文末将提供完整项目代码实现给大家参考。
二、调试器核心功能设计与实现
(一)调试机制的建立:创建与附加
调试器的首要任务是建立与目标程序的关联,主要通过**创建新进程调试**和**附加现有进程调试**两种方式实现。
创建新进程调试
通过Windows API中的`CreateProcess`函数启动目标程序,并指定调试标志`DEBUG_PROCESS`。此时调试器作为父进程,可捕获子进程的所有调试事件(如断点触发、异常抛出等)。在调试循环中,使用`WaitForDebugEvent`函数阻塞等待调试事件,解析事件类型(如`EXCEPTION_DEBUG_EVENT`、`CREATE_PROCESS_DEBUG_EVENT`),并进行相应处理(如中断程序、更新调试信息)。
附加现有进程调试
利用`OpenProcess`获取目标进程句柄,通过`DebugActiveProcess`函数附加调试器。此过程需处理权限问题,确保调试器具备足够的访问权限。附加成功后,目标进程会暂停运行,调试器接管其执行流程,后续通过`ContinueDebugEvent`恢复进程运行。
(二)汇编代码的显示与修改
1. 汇编代码显示:
- 使用 BeaEngine 反汇编引擎,将目标进程内存中的机器码转换为可读的汇编指令
- 通过 DbgUi 类实现格式化显示,包括地址、机器码、助记符和注释的对齐展示
- 使用不同颜色高亮显示不同类型的指令(如跳转、调用等)
2. 汇编代码修改:
- 使用 XEDParse 库将用户输入的汇编指令转换为机器码
- 通过 WriteProcessMemory 函数将生成的机器码写入目标进程内存
- 提供交互式的汇编模式,支持实时修改和错误检查
(三)内存与栈的查看和修改
1. 内存查看与修改:
- 使用 ReadProcessMemory 读取目标进程内存内容
- 通过 DbgUi::showMem 函数以十六进制和ASCII格式显示内存数据
- 使用 WriteProcessMemory 实现内存修改
- 支持通过 VirtualProtectEx 修改内存页属性来确保写入权限
2. 栈查看与修改:
- 通过 GetThreadContext 获取线程上下文,读取ESP/EBP等栈相关寄存器
- 使用 StackWalk64 函数遍历调用栈
- 结合 dbghelp.dll 的符号解析功能显示栈帧信息
- 同样可以通过 ReadProcessMemory/WriteProcessMemory 读写栈内存
(四)寄存器的查看与修改
1. 寄存器查看:
- 通过 GetThreadContext 获取线程上下文(CONTEXT结构体),包含所有寄存器信息
- 使用 DbgUi::showReg 函数格式化显示寄存器值
- 通过对比新旧值,用不同颜色高亮显示发生变化的寄存器
2. 寄存器修改:
- 先用 GetThreadContext 获取当前寄存器状态
- 修改 CONTEXT 结构体中对应的寄存器值
- 通过 SetThreadContext 将修改后的值写回目标线程
示例代码:
CONTEXT ct = { CONTEXT_ALL }; // 包含所有寄存器
GetThreadContext(hThread, &ct); // 获取
ct.Eax = newValue; // 修改
SetThreadContext(hThread, &ct); // 写回
本质就是利用Windows调试API中的线程上下文操作函数来实现寄存器的读写。
(五)调试事件循环
示例代码:
E_Status DbgEngine::Exec() {DEBUG_EVENT dbgEvent = { 0 };while(true) {// 等待调试事件WaitForDebugEvent(&dbgEvent, 30);// 根据事件类型处理switch(dbgEvent.dwDebugEventCode) {case EXCEPTION_DEBUG_EVENT: // 异常事件case CREATE_PROCESS_DEBUG_EVENT: // 进程创建case CREATE_THREAD_DEBUG_EVENT: // 线程创建case EXIT_PROCESS_DEBUG_EVENT: // 进程退出case LOAD_DLL_DEBUG_EVENT: // DLL加载// ... 其他事件处理}// 继续执行ContinueDebugEvent(dbgEvent.dwProcessId,dbgEvent.dwThreadId,dwStatus);}
}
三、断点功能
(一)断点类型与原理
1. 软件断点(INT 3断点)
软件断点(INT 3)的大致实现如下:
class BPSoft : public BPObject {unsigned char m_uData; // 保存原始指令字节bool Install() {// 1. 保存原始指令字节m_dbgObj.ReadMemory(m_uAddress, &m_uData, 1);// 2. 写入INT3指令(0xCC)char c = '\xCC';m_dbgObj.WriteMemory(m_uAddress, (pbyte)&c, 1);return true;}bool Remove() {// 1. 恢复原始指令m_dbgObj.WriteMemory(m_uAddress, (pbyte)&m_uData, 1);// 2. 修正EIP(因为触发断点时EIP会多加1)CONTEXT ct = { CONTEXT_CONTROL };m_dbgObj.GetRegInfo(ct);ct.Eip--;m_dbgObj.SetRegInfo(ct);return true;}
};
核心原理:
1. 设置断点时保存原始字节,并替换为0xCC(INT3指令)
2. 触发断点时恢复原始字节,并将EIP回退一个字节
3. 通过异常处理来捕获INT3中断实现断点功能
这就是最基本的软件断点实现方式。
2. 单步和硬件断点
单步和硬件断点的实现如下:
单步执行(TF断点):
class BPTF : public BPObject {bool Install() {// 设置EFLAGS的TF位(Trap Flag)CONTEXT ct = { CONTEXT_CONTROL };m_dbgObj.GetRegInfo(ct);PEFLAGS pEflags = (PEFLAGS)&ct.EFlags;pEflags->TF = 1; // 设置陷阱标志return m_dbgObj.SetRegInfo(ct);}
};
硬件断点:
class BPHard : public BPObject {bool Install() {CONTEXT ct = { CONTEXT_DEBUG_REGISTERS };// 设置调试寄存器// DR0-DR3: 存储断点地址// DR7: 控制断点类型(执行/读/写)和长度if(ct.Dr0 == 0) {ct.Dr0 = m_uAddress; // 断点地址pDbgReg7->L0 = 1; // 启用断点pDbgReg7->RW0 = m_eType; // 断点类型pDbgReg7->LEN0 = m_uLen; // 断点长度}return m_dbgObj.SetRegInfo(ct);}
};
主要特点:
- 单步:通过设置EFLAGS的TF位,每执行一条指令就触发异常
- 硬件断点:利用CPU的调试寄存器(DR0-DR7),支持执行/读/写断点,最多4个
优势:
- 单步:不修改代码,适合追踪执行流程
- 硬件断点:不修改内存,适合监控内存访问,且数量有限
这两种断点都是通过CPU提供的硬件功能来实现的,比软件断点更特殊。
4. 内存访问断点
内存访问断点的大致实现如下:
class BPAcc : public BPObject {E_BPType m_eType; // 断点类型(读/写/执行)uint m_uLen; // 监视长度DWORD m_oldProtect; // 原始页面属性bool Install() {// 1. 修改内存页属性,触发访问异常VirtualProtectEx(m_dbgObj.m_hCurrProcess,(LPVOID)m_uAddress,m_uLen,PAGE_GUARD, // 设置为Guard页&m_oldProtect);return true;}bool Remove() {// 恢复原始页面属性VirtualProtectEx(m_dbgObj.m_hCurrProcess,(LPVOID)m_uAddress,m_uLen,m_oldProtect,&dwOldProtect);return true;}bool IsHit() {// 根据异常信息判断访问类型(读/写/执行)switch(m_eType) {case breakpointType_acc_r: // 读断点case breakpointType_acc_w: // 写断点case breakpointType_acc_e: // 执行断点}}
};
核心原理:
1. 通过修改内存页属性(PAGE_GUARD)来监控内存访问
2. 当目标地址被访问时触发异常
3. 在异常处理中判断访问类型(读/写/执行)
4. 支持设置监视范围的长度
这种方式可以监控较大范围的内存访问,但会影响性能。
(二)断点管理与界面交互
1. 断点管理:
- 通过`BreakpointEngine`类管理断点列表,支持软件断点(INT3)、硬件断点(DR)、内存断点和TF单步断点
- 软件断点通过替换指令为0xCC实现,硬件断点使用调试寄存器,内存断点修改页面属性
- 每个断点都继承自`BPObject`基类,实现`Install()`、`Remove()`等统一接口
2. 界面交互:
- 使用命令行方式接收用户输入,如'b'设置断点,'l'显示断点列表,'g'运行等
- 通过`DbgUi`类处理显示格式化,包括断点位置高亮、寄存器变化显示等
- 使用Windows控制台API实现颜色显示和布局排版
核心代码示例:
// 断点管理
BPObject* AddBreakPoint(uaddr uAddress, E_BPType eType);
bool DeleteBreakpoint(uint uIndex);// 界面交互
void showBreakPointList();
void showReg(const CONTEXT& ct);
本质是将断点管理功能与命令行界面结合,提供友好的调试体验。
四、高级功能
(1)条件断点功能:
- 实现在 `BPObject` 类中,通过 `SetCondition()` 和 `IsHit()` 方法支持条件断点
- 使用 `Expression` 类来解析和计算条件表达式
- 断点类型包括:
- 软件断点 (`BPSoft`): 通过写入 INT3 指令(0xCC)实现
- 硬件断点 (`BPHard`): 利用调试寄存器实现
- 内存访问断点 (`BPAcc`): 监控内存访问
- 单步执行断点 (`BPTF`): 利用 TF 标志实现
(2)反反调试技术:
- 在 `HidePEB.h` 中实现了隐藏 PEB 调试标志:
- 修改 `BeingDebugged` 字段为 0
- 清除 `NtGlobalFlag` 标志
- 在 `DbgObject` 类中实现了 API Hook:
- 通过 `HOOKObject` 和 `HOOKEngine` 类管理 Hook
- 可以 Hook 关键 API 如 `IsDebuggerPresent`
- 支持保存和恢复原始函数数据
(3)插件支持:
- 在 `AddPlugin.h` 中实现了插件系统:
- 定义了插件结构体 `PLUGIN_T`,包含:
- 插件名称
- DLL 实例句柄
- 插件函数指针
- 通过 `g_pv` 结构体管理插件列表
- `load_plugin()` 函数用于加载插件:
- 加载插件 DLL
- 获取插件导出函数
- 添加到插件列表
- 插件接口:
- 插件需要导出 `funTest` 函数
- 可以通过 `.load <dll name>` 命令动态加载插件
- 支持最多 50 个插件同时加载
五、附加功能
1. 导入导出表解析:完整实现,支持32位和64位PE文件
2. 符号解析:通过dbghelp.dll实现,支持符号加载和解析
3. 源码调试:有基础实现,但可能功能不够完整
4. DUMP功能:支持内存dump和文件导出
5. 其他功能:
- 断点管理:完整支持
- 堆栈显示:基本实现
- 代码高亮:支持控制台颜色显示
六、开发环境与实现概要
6.1 环境配置
- 操作系统:Windows 10(64位),支持x86和x64架构调试。
- 开发工具:Visual Studio 2015或以上,使用C++语言结合Windows SDK开发。
6.2 界面设计
采用dos窗口显示
6.3 实现概要
这是一个基于Windows平台的用户态调试器,使用C++开发,实现了调试器的核心功能,包括断点管理、内存操作、符号解析等功能。
核心功能模块
(1)调试引擎核心 (DbgEngine类)
- 进程调试控制:创建/附加进程
- 调试事件处理循环
- 异常处理机制
- 调试会话管理
(2)断点系统 (BreakpointEngine类)
实现了四种类型的断点:
1. 软件断点(BPSoft)
- 使用INT3指令(0xCC)实现
- 通过替换目标地址的指令字节实现
2. 硬件断点(BPHard)
- 利用CPU的调试寄存器(DR0-DR7)
- 支持执行、读写断点
3. 内存访问断点(BPAcc)
- 通过修改内存页属性实现
- 支持读/写/执行权限控制
4. 单步执行断点(BPTF)
- 利用EFLAGS寄存器的TF位
- 实现指令级单步执行
(3)符号处理系统
- 使用dbghelp.dll提供的功能
- 支持调试符号的加载和解析
- 提供符号信息查询
- 支持调用栈回溯
(4)反汇编系统
结合使用三个重要的外部库:
1. BeaEngine 4.1
- x86/x64指令反汇编
- 支持多种指令集
2. dbghelp.dll
- 调试符号处理
- PE文件分析
- 调用栈分析
3. XEDParse.dll
- 指令编码/解码
- 汇编指令解析
- 机器码生成
6.4 技术特点
(1)系统架构
- 采用面向对象设计
- 模块化结构清晰
- 良好的继承和多态设计
(2)关键技术
1. Windows调试API的使用
- CreateProcess/DebugActiveProcess
- WaitForDebugEvent
- ReadProcessMemory/WriteProcessMemory
- VirtualProtectEx
- GetThreadContext/SetThreadContext
2. 断点实现技术
- 指令修改(软件断点)
- 调试寄存器配置(硬件断点)
- 内存属性控制(内存断点)
- 标志位设置(单步执行)
(3)高级功能
- 条件断点支持
- 一次性断点
- 多种断点类型
- 表达式计算器
- 反汇编显示
- 内存/寄存器操作
6.5 项目特色
1. 完整性:实现了调试器的所有核心功能
2. 可扩展性:模块化设计便于功能扩展
3. 稳定性:包含异常处理和错误恢复机制
4. 实用性:支持多种调试场景和需求
6.6 技术依赖
- Windows SDK
- BeaEngine 4.1 (反汇编引擎)
- dbghelp.dll (调试符号支持)
- XEDParse.dll (指令解析)
七、项目展示及完整代码参考
(一)功能截图说明
- 功能菜单:(如图1所示)。
图1
- 单步运行:(如图2所示)。
图2
- 查看及修改汇编(如图3所示)。
图3
- 查看及修改寄存器(如图4所示)。
图4
- 查看栈(如图5所示)
图5
- 断点标记:用红色标记断点位置(如图6所示)。
图6
(二)完整代码参考
https://download.csdn.net/download/linshantang/90530517
八、总结
本文介绍的调试器通过Windows API和C/C++语言实现了完整的调试功能链,从基础的进程控制到高级的反反调试和插件机制,覆盖了开发者在调试过程中的核心需求。其设计思路和实现方法不仅适用于Windows平台,也为其他操作系统的调试工具开发提供了参考。
这个调试器项目主要收获:
1. Windows调试器的核心实现原理,包括断点机制、进程控制和内存操作
2. 反调试对抗技术,如PEB结构修改和API Hook的实现
3. 良好的软件架构设计,展示了如何构建可扩展的模块化系统
4. Windows系统底层知识,包括汇编、PE文件格式和系统API的使用
相关文章:

【第52节】Windows编程必学之从零手写C++调试器下篇(仿ollydbg)
目录 一、引言 二、调试器核心功能设计与实现 三、断点功能 四、高级功能 五、附加功能 六、开发环境与实现概要 七、项目展示及完整代码参考 八、总结 一、引言 在软件开发领域,调试器是开发者不可或缺的工具。它不仅能帮助定位代码中的逻辑错误࿰…...

uni-app学习笔记五--vue3插值表达式的使用
vue3快速上手导航:简介 | Vue.js 模板语法 插值表达式 最基本的数据绑定形式是文本插值,它使用的是“Mustache”语法 (即双大括号): <span>Message: {{ msg }}</span> 双大括号标签会被替换为相应组件实例中 msg 属性的值。同…...

C++类与对象(二):六个默认构造函数(一)
在学C语言时,实现栈和队列时容易忘记初始化和销毁,就会造成内存泄漏。而在C的类中我们忘记写初始化和销毁函数时,编译器会自动生成构造函数和析构函数,对应的初始化和在对象生命周期结束时清理资源。那是什么是默认构造函数呢&…...
OpenCV CUDA 模块中在 GPU 上对图像或矩阵进行 翻转(镜像)操作的一个函数 flip()
操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 cv::cuda::flip 是 OpenCV 的 CUDA 模块中的一个函数,用于在 GPU 上对图像或矩阵进行 翻转(镜像)操作。它类似…...
基于大模型的原发性醛固酮增多症全流程预测与诊疗方案研究
目录 一、引言 1.1 研究背景与意义 1.2 国内外研究现状 1.3 研究目的与方法 二、原发性醛固酮增多症概述 2.1 疾病定义与发病机制 2.2 临床表现与诊断标准 2.3 流行病学特征 三、大模型预测原理与技术 3.1 大模型简介 3.2 预测原理与算法 3.3 数据收集与预处理 四…...

从逻辑学视角探索数学在数据科学中的系统应用:一个整合框架
声明:一家之言,看个乐子就行。 图表采用了两个维度组织知识结构: 垂直维度:从上到下展示了知识的抽象到具体的演进过程,分为四个主要层级: 逻辑学基础 - 包括数理逻辑框架和证明理论数学基础结构 - 涵盖…...

Matplotlib 完全指南:从入门到精通
前言 Matplotlib 是 Python 中最基础、最强大的数据可视化库之一。无论你是数据分析师、数据科学家还是研究人员,掌握 Matplotlib 都是必不可少的技能。本文将带你从零开始学习 Matplotlib,帮助你掌握各种图表的绘制方法和高级技巧。 目录 Matplotli…...

如何有效追踪需求的实现情况
有效追踪需求实现情况,需要清晰的需求定义、高效的需求跟踪工具、持续的沟通反馈机制,其中高效的需求跟踪工具尤为关键。 使用需求跟踪工具能确保需求实现进度可视化、提高团队协作效率,并帮助识别和管理潜在风险。例如,使用专业的…...

自动驾驶技术栈——DoIP通信协议
一、DoIP协议简介 DoIP,英文全称是Diagnostic communication over Internet Protocol,是一种基于因特网的诊断通信协议。 DoIP协议基于TCP/IP等网络协议实现了车辆电子控制单元(ECU)与诊断应用程序之间的通信,常用于汽车行业的远程诊断、远…...

C++ 与 Go、Rust、C#:基于实践场景的语言特性对比
目录 编辑 一、语法特性对比 1.1 变量声明与数据类型 1.2 函数与控制流 1.3 面向对象特性 二、性能表现对比编辑 2.1 基准测试数据 在计算密集型任务(如 10⁷ 次加法运算)中: 在内存分配测试(10⁵ 次对象创建…...
Docker 中的 DNS 解析机制
在 Docker 容器化环境中,网络连接是至关重要的,而 DNS(Domain Name System,域名系统)解析则是网络通信的基础。容器需要能够解析内部服务名称以及外部域名,以便与其他容器或外部世界进行交互。理解 Docker 如何处理 DNS 请求,可以帮助我们更好地配置和排查网络问题。 D…...
数字化工厂中央控制室驾驶舱系统 API接口文档
数字化工厂中央控制室驾驶舱系统 API接口文档 本文档详细描述了数字化工厂中央控制室驾驶舱系统的API接口规范,包括中端服务提供的数据接口和算法接口。 1. 通用规范 1.1 基础URL 后端服务: http://localhost:8000中端服务数据API: http://localhost:8001中端服…...

如何更改默认字体:ONLYOFFICE 协作空间、桌面编辑器、文档测试示例
在处理办公文件时,字体对提升用户体验至关重要。本文将逐步指导您如何在 ONLYOFFICE 协作空间、桌面应用及文档测试示例中自定义默认字体,以满足个性化需求,更好地掌控文档样式。 关于 ONLYOFFICE ONLYOFFICE 是一个国际开源项目,…...

设计模式之工厂模式(二):实际案例
设计模式之工厂模式(一) 在阅读Qt网络部分源码时候,发现在某处运用了工厂模式,而且编程技巧也用的好,于是就想分享出来,供大家参考,理解的不对的地方请多多指点。 以下是我整理出来的类图: 关键说明&#x…...

基于VeRL源码深度拆解字节Seed的DAPO
1. 背景与现状:从PPO到GRPO的技术演进 1.1 PPO算法的基础与局限 Proximal Policy Optimization(PPO)作为当前强化学习领域的主流算法,通过重要性采样比率剪裁机制将策略更新限制在先前策略的近端区域内,构建了稳定的…...

zst-2001 历年真题 软件工程
软件工程 - 第1题 b 软件工程 - 第2题 c 软件工程 - 第3题 c 软件工程 - 第4题 b 软件工程 - 第5题 b 软件工程 - 第6题 0.未完成:未执行未得到目标。1.已执行:输入-输出实现支持2.已管理:过程制度化,项目遵…...
WSL 安装 Debian 12 后,Linux 如何安装 redis ?
在 WSL 的 Debian 12 上安装 Redis 的步骤如下: 1. 更新系统包列表 sudo apt update && sudo apt upgrade -y2. 安装 Redis sudo apt install redis-server -y3. 启动 Redis 服务 sudo systemctl start redis4. 设置开机自启 sudo systemctl enable red…...
在Ubuntu系统下编译OpenCV 4.8源码
编译OpenCV 4.8源码可以为你提供更高的灵活性和优化性能,适合特定的需求。以下是详细的步骤,指导你在Ubuntu系统上编译和安装OpenCV 4.8。 1. 安装必要的依赖 首先,确保你的系统已经安装了所有必要的依赖项。 sudo apt update sudo apt in…...
Arduino快速入门
Arduino快速入门指南 一、硬件准备 选择开发板: 推荐使用 Arduino UNO(兼容性强,适合初学者),其他常见型号包括NANO(体积小)、Mega(接口更多)。准备基础元件:…...

基于WSL用MSVC编译ffmpeg7.1
在windows平台编译FFmpeg,网上的大部分资料都是推荐用msys2mingw进行编译。在win10平台,我们可以采用另一种方式,即wslmsvc 实现window平台的ffmpeg编译。 下面将以vs2022ubuntu22.04 为例,介绍此方法 0、前期准备 安装vs2022 &…...

java命令行打包class为jar并运行
1.创建无包名类: 2.添加依赖jackson 3.引用依赖包 4.命令编译class文件 生成命令: javac -d out -classpath lib/jackson-core-2.13.3.jar:lib/jackson-annotations-2.13.3.jar:lib/jackson-databind-2.13.3.jar src/UdpServer.java 编译生成class文件如下 <...

vue注册用户使用v-model实现数据双向绑定
定义数据模型 Login.vue //定义数据模型 const registerData ref({username: ,password: ,confirmPassword: })使用 v-model 实现数据模型的key与注册表单中的元素之间的双向绑定 <!-- 注册表单 --><el-form ref"form" size"large" autocompl…...
Android学习之响应式编程
本篇基于DeepSeek 搜索结果修改。 一、响应式编程基础认知 1.1 为什么需要响应式编程? 在传统的Android开发中,我们经常会遇到以下痛点: // 传统方式处理数据变化 button.setOnClickListener {// 触发网络请求fetchDataFromNetwork { res…...
如何使用极狐GitLab 软件包仓库功能托管 helm chart?
极狐GitLab 是 GitLab 在中国的发行版,关于中文参考文档和资料有: 极狐GitLab 中文文档极狐GitLab 中文论坛极狐GitLab 官网 软件包库中的 Helm charts (BASIC ALL) WARNING:Helm chart 库正在开发中,由于功能有限,尚未准备好用…...
中国古代史4
东汉 公元25年,刘秀建立东汉,定都洛阳,史称光武中兴 白马寺:汉明帝时期建立,是佛教传入中国后兴建的第一座官办寺院,有中国佛教的“祖庭”和“释源”之称,距今1900多年历史 班超—西域都护—投…...

Nacos源码—8.Nacos升级gRPC分析六
大纲 7.服务端对服务实例进行健康检查 8.服务下线如何注销注册表和客户端等信息 9.事件驱动架构源码分析 一.处理ClientChangedEvent事件 也就是同步数据到集群节点: public class DistroClientDataProcessor extends SmartSubscriber implements DistroDataSt…...
基于Vue3.0的高德地图api教程005:实现绘制线并编辑功能
文章目录 6、绘制多段线6.1 绘制多段线6.1.1 开启绘制功能6.1.2 双击完成绘制6.1.3 保存到数据库6.2 修改多段线6.2.1 点击线,进入编辑模式6.2.2 编辑线6.3 完整代码6、绘制多段线 6.1 绘制多段线 6.1.1 开启绘制功能 实现代码: const changeSwitchDrawPolyline = ()=>…...

SpringBoot 自动装配原理 自定义一个 starter
目录 1、pom.xml 文件1.1、parent 模块1.1.1、资源文件1.1.1.1、resources 标签说明1.1.1.2、从 Maven 视角:资源处理全流程 1.1.2、插件 1.2、dependencies 模块 2、启动器3、主程序3.1、SpringBootApplication 注解3.2、SpringBootConfiguration 注解3.2.1、Con…...

【C++进阶篇】多态
深入探索C多态:静态与动态绑定的奥秘 一. 多态1.1 定义1.2 多态定义及实现1.2.1 多态构成条件1.2.1.1 实现多态两个必要条件1.2.1.2 虚函数1.2.1.3 虚函数的重写/覆盖1.2.1.4 协变1.2.1.5 析构函数重写1.2.1.6 override和final关键字1.2.1.7 重载/重写/隐藏的对⽐ 1…...
Redis 基础详解:从入门到精通
在当今互联网应用开发领域,数据存储与处理的性能和效率至关重要。Redis(Remote Dictionary Server)作为一款开源的、基于内存的键值存储系统,凭借其出色的性能和丰富的功能,被广泛应用于数据库、缓存、消息中间件等场景…...