想法15 分钟阅读编辑本文 ↗

从 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

判断是否真正掌握:

  1. 能不能不用 AI 写出来?
  2. 能不能解释为什么?
  3. 出 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

这才是后续几年持续向下扎根的主线。