从 Qt 业务开发走向 Linux C++:后续学习路线
从标准 C++ 重新夯实基础,逐步补齐 Linux、网络、系统编程与设备通信能力,最终形成 Linux C++ / 嵌入式 Linux 工程能力。
从 Qt 业务开发走向 Linux C++:后续学习路线
0. 当前状态
目前已有多年 C++ / Qt 实际项目经验,可以完成:
- Qt Widgets 业务开发
- 信号槽与事件驱动
- QThread / Qt 多线程
- TCP / UDP / 组播 / WebSocket
- 二进制协议解析
- 串口及设备通信
- MySQL / SQLite
- Windows 环境下的问题定位与联调
- 在已有大型项目、框架中阅读代码并修改业务
当前主要问题不是"不会编程",而是长期工作集中在:
阅读已有框架 → 修改业务 → 调用 Qt / 第三方接口 → 联调 → 修 Bug
导致标准 C++、Linux、操作系统、底层网络以及独立工程设计能力没有持续增长。
因此后续学习不再围绕"学更多 Qt API",而是逐步完成:
Qt C++ 开发 → 通用 C++ 工程师 → Linux C++ → 系统/设备开发 → 嵌入式 Linux
1. 总体原则
1.1 暂停 Qt 依赖
第一阶段学习项目禁止使用 Qt。
熟悉的:
QString
QByteArray
QVector
QMap
QFile
QThread
QMutex
QScopedPointer
QTcpSocket
QUdpSocket
重新使用:
std::string
std::vector
std::array
std::map
std::unordered_map
std::fstream
std::filesystem
std::thread
std::mutex
std::unique_ptr
std::shared_ptr
Linux 阶段进一步使用:
open
read
write
socket
bind
listen
accept
recv
send
poll
epoll
mmap
目的不是抛弃 Qt,而是做到:
不依赖 Qt,也能够独立完成一个完整 C++ 程序。
Qt 最终变成工具,而不是能力边界。
1.2 统一技术基线
整个路线锁定 C++17 作为主标准(嵌入式 Linux 工具链对 C++17 支持最稳), 同时留意 C++20 / C++23 的 coroutine、concept、ranges,遇到合适场景再引入。
1.3 每个阶段的验收标准
每个阶段不按"看完资料"判断完成,而是提前写出可验证的验收标准,例如:
- 不看资料手写一个带移动语义的容器类,并解释每个成员函数存在的理由
- 从零完成一个 epoll TCP Server,能通过异常输入测试
时间安排以阶段为单位推进,不把月份当成硬性截止:某个月落后了,调整的是 节奏而不是标准。标准只能提高,不能降低。
1.4 每个阶段的固定输出
每个阶段结束时产出三样东西:
- 一段能复用的代码,进入 CppDeviceLab
- 一篇发布到本站的复盘文章,说明取舍与踩过的坑
- 一个小型开源项目的源码阅读笔记(mongoose、libevent 级别)
2. Phase 1:Standard C++ 基础回炉
预计时间:6~8 周
目标:
恢复现代 C++ 思维,重新建立对象、内存、资源、所有权和 STL 的完整知识体系。
2.1 对象与生命周期
重点:
- 栈与堆
- 对象生命周期
- 构造函数
- 析构函数
- 拷贝构造
- 拷贝赋值
- 移动构造
- 移动赋值
- Rule of 0
- Rule of 3
- Rule of 5
要求能够回答:
- 一个对象什么时候创建?
- 什么时候销毁?
- 谁拥有它?
- 谁负责释放?
2.2 RAII
重点:
- 什么是资源
- 为什么资源不限于内存
- RAII 的本质
- 构造获取资源
- 析构释放资源
- 异常安全
- Scope Based Resource Management
资源包括:
Memory
File
Socket
Mutex
Thread
Database Connection
Device Handle
最终建立思维:
Resource Lifetime = Object Lifetime
2.3 智能指针与所有权
掌握:
std::unique_ptr
std::shared_ptr
std::weak_ptr
std::make_unique
std::make_shared
重点不是 API,而是:
Ownership
Lifetime
Reference Counting
Circular Reference
必须能够解释:
为什么这里应该使用 unique_ptr?
而不是仅仅回答:
因为智能指针不会内存泄漏。
2.4 左值、右值与移动语义
学习:
lvalue
rvalue
lvalue reference
rvalue reference
std::move
std::forward
move constructor
move assignment
重点理解 std::move(obj) 本身并没有"移动资源"。
它本质上进行类型转换,真正的资源转移由移动构造或移动赋值完成。
结合 std::vector<T> 观察:
- copy
- move
- realloc
- noexcept
之间的关系。
2.5 STL 容器
重新熟练:
std::vector
std::array
std::deque
std::list
std::map
std::unordered_map
std::set
std::unordered_set
std::queue
std::priority_queue
重点掌握:
- 底层数据结构
- 时间复杂度
- 内存布局
- iterator
- iterator invalidation
- size / capacity
- reallocation
- 连续内存
- Hash Table
- Red-Black Tree
能够根据场景解释为什么选择某个容器。
2.6 STL Algorithm 与 Lambda
学习:
std::find
std::find_if
std::sort
std::transform
std::accumulate
std::remove_if
std::for_each
结合:
lambda
capture
std::function
逐渐减少传统手写循环和 Qt 风格操作。
2.7 模板基础
第一阶段掌握:
Function Template
Class Template
Template Parameter
Instantiation
Specialization
Variadic Template 基本概念
暂时不深入复杂 TMP、SFINAE 黑魔法和复杂 Type Traits,后续遇到实际需求再深入。
2.8 多态与对象模型
重新理解:
virtual
override
abstract class
dynamic dispatch
vtable
vptr
object slicing
RTTI
dynamic_cast
重点理解:
- C++ 的运行时多态付出了什么成本?
- 什么时候应该使用继承?
- 什么时候应该使用组合?
2.9 内存模型与对象布局
在对象模型基础上补充:
Memory Model 基本概念
Cache Line 与伪共享
结构体内存布局与 padding
alignment / alignas
重点回答:
- 为什么一个结构体的字段顺序会影响大小?
- 多线程下两个变量放进同一缓存行会发生什么?
这些问题在 Phase 2 并发阶段会再次相遇。
2.10 验收标准
- 不查资料实现一个带拷贝/移动语义的小容器类,并能解释每个特殊成员函数 存在的理由
- 能讲清 vtable / vptr 的布局与代价,以及继承与组合的选择依据
- 所有练习代码在 ASan / UBSan 开启下运行无报告(这两个检查器从本阶段 起默认开启)
3. Phase 2:C++ 并发编程
预计:3~4 周
目标:
从 QThread 思维切换到标准 C++ 并发模型。
学习:
std::thread
std::mutex
std::lock_guard
std::unique_lock
std::condition_variable
std::atomic
std::future
std::async
重点理解:
Race Condition
Deadlock
Critical Section
Lock Granularity
Memory Visibility
Thread Lifetime
实践项目:BlockingQueue
自己实现:
Producer
↓
BlockingQueue
↓
Consumer
要求:
- 多 Producer
- 多 Consumer
- condition_variable
- 正确退出
- 无 Busy Waiting
- 无死锁
- 无数据竞争
- doctest / Catch2 单元测试覆盖
- TSan 压测无报告
之后扩展为 ThreadPool。
验收标准
- BlockingQueue 多 Producer / 多 Consumer 在 TSan 下压测无报告
- 能画出线程生命周期,解释锁粒度选择与条件变量唤醒丢失问题
4. Phase 3:Linux 基础
预计:6~8 周
目标:
脱离 Windows + Qt Creator,也能够完成完整 C++ 开发。
开发环境:
Ubuntu
GCC / G++
CMake
Git
GDB
VS Code / Vim
4.1 Linux 基础
掌握:
Linux 文件系统
权限
用户
进程
线程
环境变量
管道
重定向
信号
常用工具:
ps
top
htop
grep
find
sed
awk
lsof
ss
netstat
strace
ldd
nm
objdump
4.2 CMake
能够独立建立:
project/
├── CMakeLists.txt
├── include/
├── src/
├── tests/
└── third_party/
掌握:
target 与 target-based 组织
add_library / add_executable
target_include_directories
target_link_libraries
find_package
install / export
CTest
CMake Presets
Debug / Release
static library
shared library
先建立现代 CMake 习惯(一切围绕 target,不碰全局变量式写法),再为后续 交叉编译预留位置:Phase 7 会引入 Toolchain 文件,届时编译的是同一套 CMake 工程。
不再依赖 IDE 自动完成工程配置。
4.3 GDB
重点掌握:
breakpoint
step
next
continue
backtrace
frame
watch
thread
core dump
目标:
程序 Segmentation Fault 后,第一反应不是让 AI 找 Bug,而是自己先拿到调用栈。
配合 ASan / UBSan 与 core dump,把内存错误定位到具体行。
4.4 Linux 资源与文件 IO
学习:
open
close
read
write
lseek
stat
mmap
理解:
File Descriptor
Blocking IO
Buffer
Page Cache
mmap
4.5 链接器与动态库
理解:
symbol
relocation
静态链接与动态链接
soname 与版本
-l 与 -Wl 常用选项
结合 nm 与 ldd 观察一个真实库的导出符号与依赖关系。
验收标准
- 独立用 CMake 建立包含库与测试的工程,Debug / Release 双配置可用
- 用 GDB + ASan 定位并修复一个真实内存错误
5. Phase 4:Linux 网络编程
预计:6~8 周
这是后续重点方向之一。
5.1 TCP / UDP 基础重新学习
从:
QTcpSocket
QUdpSocket
下降到:
socket
bind
listen
accept
connect
send
recv
sendto
recvfrom
close
理解 Socket 本质。
5.2 TCP 深入
重点:
Three-Way Handshake
Four-Way Termination
TIME_WAIT
TCP State
Sliding Window
Flow Control
Congestion Control
Nagle
KeepAlive
结合 Wireshark 与 tcpdump 实际抓包验证。
5.3 半包与粘包
自己设计二进制协议:
Magic
Version
Type
Length
Sequence
Payload
CRC
实现:
Byte Stream
↓
Receive Buffer
↓
Frame Detection
↓
Length Check
↓
Complete Packet
↓
Protocol Parser
必须支持:
- 一个 recv 半帧
- 一个 recv 多帧
- 帧跨多个 recv
- 错误 Magic
- 超长 Length
- 数据恢复
5.4 IO Multiplexing
按照顺序:
Blocking Socket
↓
Non-Blocking Socket
↓
select
↓
poll
↓
epoll
重点理解:
LT
ET
EAGAIN
Non-blocking
Event Loop
最终自己实现:
epoll TCP Server
而不是直接使用网络框架。
验收标准
- 从零实现 epoll TCP Server,半帧、超长帧、断连重连等异常输入不崩溃
- 用 tcpdump 观察并解释三次握手与四次挥手
6. Phase 5:Linux 系统编程
预计:5~7 周
学习:
Process
fork
exec
wait
pipe
signal
shared memory
mmap
IPC
Unix Domain Socket
进一步理解:
Process vs Thread
User Space vs Kernel Space
Context Switch
Virtual Memory
System Call
这一阶段开始真正补操作系统基础。
性能分析入门
掌握:
perf stat
perf record
Flame Graph
目标:
能解释一段热点代码的时间花在哪里,而不是靠猜。
验收标准
- 用 perf 找出自己程序的真实热点,并给出优化前后的对比证据
7. Phase 6:设备通信
完成前面基础以后,开始利用已有工作经验向设备方向深入。
重点:
Serial
RS232
RS422
RS485
CAN
TCP / UDP Device
Linux 下学习:
/dev/tty*
termios
baud rate
parity
stop bit
blocking / non-blocking
不只是做到"能收到数据",还要理解:
Buffer
Timeout
Frame
CRC
Retry
Reconnect
State Machine
把解析逻辑抽象成可复用的状态机模块,让 TCP / Serial / CAN 共用同一套 Frame 处理代码。
验收标准
- 同一套 Parser 同时驱动 TCP 与 Serial 两个通道
- 半帧、错 Magic、超长 Length 等异常输入测试全部通过
8. Phase 7:ARM / 嵌入式 Linux
完成 Linux C++ 基础后再进入。
不要一开始直接钻 STM32。
学习:
ARM 基础
Cross Compile
Toolchain
RootFS
Boot 基础
Linux Device
GPIO
UART
I2C
SPI
理解:
Application
↓
System Call
↓
Kernel
↓
Driver
↓
Hardware
第一阶段目标不是成为驱动工程师。
而是成为:
能够在 ARM Linux 设备上独立开发、部署、调试 C++ 软件的工程师。
进入本阶段第一周就购置开发板(树莓派或同价位国产 ARM 板),所有练习直接 在真实硬件上完成,不等到 V1.0。
掌握:
Device Tree 基础
Buildroot 或 Yocto(二选一,建议先 Buildroot)
U-Boot 基础流程
交叉编译与部署
验收标准
- 用 Buildroot 构建一个可启动的 RootFS
- 在板子上部署并运行 CppDeviceLab 的 TCP Server
9. 长期综合项目:CppDeviceLab
整个学习过程不创建大量一次性 Demo,而是维护一个长期项目:
CppDeviceLab
持续迭代:
V0.1 C++17 / CMake / Standard Library
↓
V0.2 RAII / Smart Pointer / STL
↓
V0.3 Thread / BlockingQueue / ThreadPool
↓
V0.4 TCP Client / TCP Server
↓
V0.5 Binary Protocol / Packet Parser
↓
V0.6 Device Simulator(作为解析器的测试对端,同步开发)
↓
V0.7 Non-Blocking Socket / epoll
↓
V0.8 SQLite / Logging / Configuration / Heartbeat
↓
V0.9 Serial Device
↓
V1.0 ARM Linux / Raspberry Pi
最终形成:
Device
│
Serial / Network
│
▼
┌──────────────────────────┐
│ ARM Linux │
│ │
│ DeviceManager │
│ ProtocolParser │
│ ThreadPool │
│ DataManager │
│ SQLite │
│ TCP Server │
│ Logging │
└────────────┬─────────────┘
│
TCP
│
▼
┌──────────────────────────┐
│ PC Qt Client │
│ │
│ Monitor / Control / UI │
└──────────────────────────┘
此时 Qt 再重新出现,但 Qt 只负责 Presentation / Client,核心系统不依赖 Qt。
每个版本保持固定流程:设计评审(接口、模块边界、错误处理策略)→ 实现 → 测试 → 复盘。错误处理以"错误码 + 返回值"为主,异常只用于构造等无法返回 的场景,方便后续向嵌入式环境迁移。
10. Codex 使用原则
Codex 不作为"代写工具",而作为:
Teacher
Reviewer
Interviewer
Debugger
Requirement Provider
Bug Generator
10.1 核心代码禁止直接生成
Codex 可以:
- 创建 CMake 脚手架
- 生成测试数据
- 创建 Mock Device
- Code Review
- 设计测试
- 提供 Hint
- 制造 Bug
- 提问
Codex 不直接完成:
- 核心数据结构
- Ownership 设计
- Protocol Parser
- Thread Model
- Socket 核心逻辑
- epoll Event Loop
- 系统架构
10.2 固定学习循环
每个知识点:
Learn
↓
Explain
↓
Implement
↓
Test
↓
Debug
↓
Review
↓
Refactor
↓
Explain Again
判断是否真正掌握:
- 能不能不用 AI 写出来?
- 能不能解释为什么?
- 出 Bug 后能不能自己定位?
三项全部满足,才算完成。
11. 学习状态标记
所有知识点使用:
🟢 掌握
能独立实现 + 能解释 + 能接受追问
🟡 模糊
使用过,但原理不够清楚
🔴 不会
需要重新系统学习
不要按照"看过"判断完成度。
12. 时间规划
以下时间为参照节奏而非硬性节点:进度以各阶段的验收标准为准,某个月落后 了,调整节奏、不降低标准。
阶段一:Standard C++(预计 6~8 周)
重点:
Standard C++
STL
RAII
Smart Pointer
Move Semantics
Object Lifetime
目标:
恢复标准 C++ 手感。
阶段二:并发与 Linux(预计 8~10 周)
重点:
std::thread
Concurrency
Linux
CMake
GDB
Linux IO
目标:
可以脱离 Qt / Windows 独立开发 C++ 程序。
阶段三:Linux 网络(预计 6~8 周)
重点:
Socket
TCP
UDP
Non-Blocking
select
poll
epoll
Protocol
目标:
从 Qt 网络编程升级到 Linux 网络编程。
阶段四:综合工程(预计 3 个月以上)
重点:
CppDeviceLab
Linux System Programming
Device Communication
ARM Linux
目标:
将零散知识整合为真正的工程能力。
13. 后续职业方向
学习过程中暂时不强行决定"必须转嵌入式"。
优先建立公共基础:
Modern C++
+
Linux
+
Network
+
Concurrency
+
System Programming
完成以后,可以根据兴趣与岗位情况选择:
路线 A
Linux C++
→ 网络/系统软件
→ 高性能 C++
路线 B
Linux C++
→ Device
→ ARM
→ Embedded Linux
路线 C
Linux C++
→ Industrial Software
→ Device Communication
→ Qt Client
路线 D
Linux C++
→ Robotics / Edge Device
→ Embedded / Control
无论最终选择哪条路线,前半段学习内容都不会浪费。
14. 最终目标
未来不再把自己的职业能力描述为:
熟练使用 Qt 进行 C++ 开发。
而是:
具备扎实的现代 C++、Linux、多线程、网络与设备通信能力,能够独立完成 Linux/ARM 环境下 C++ 软件的设计、开发、调试和问题定位,并可使用 Qt 完成上位机及可视化客户端开发。
Qt 从:
核心身份
逐渐变成:
工具之一。
真正需要积累的是:
C++ + Linux + System + Network + Device
这才是后续几年持续向下扎根的主线。