C++/QT 开发技能树详解
一、 编程语言 (C++)
1. C++基础语法(数据类型、模板、命名空间)
是什么: 这是构建C++程序的基石。数据类型定义了变量存储的数据种类和大小;模板允许编写与数据类型无关的通用代码;命名空间用于避免大型项目中的名称冲突。
如何理解:
数据类型: 如
int
,double
,char
是基础类型;std::string
,std::vector
是标准库定义的复杂类型。理解它们的内存占用和操作代价对性能优化至关重要。模板: 可以把它理解为一个“代码模具”。比如您项目中的
std::vector<int>
和std::vector<std::string>
,编译器会根据这个“模具”生成两份分别处理int和string的代码。这是C++实现泛型编程的核心。命名空间: 类似于文件系统的目录。
std::cout
意味着在std
这个“目录”下找cout
。您也可以创建自己的命名空间来组织代码,防止和第三方库的符号冲突。
如何使用:
在定义变量时选择最合适的数据类型。
使用模板来编写通用函数(如
template <typename T> T max(T a, T b)
)和通用类。在自己的库或模块中使用
namespace MyProject { ... }
来封装代码。使用using namespace std;
需谨慎,尤其在头文件中。
2. 指针
是什么: 指针是一个变量,其值是另一个变量的内存地址。
如何理解: 指针就是地址。
它提供了直接操作内存的能力,非常强大但也容易出错(如空指针、野指针)。在C++中,它常用于动态内存分配、数组遍历、函数传参(避免拷贝大对象)等。
如何使用:
动态分配内存:
int *ptr = new int;
,记得用delete ptr;
释放。传递函数参数:
void modifyValue(int *ptr) { *ptr = 10; }
,允许函数修改外部变量的值。访问数组:数组名本质上就是一个指向数组首元素的指针。
现代C++建议: 优先使用智能指针 (
std::unique_ptr
,std::shared_ptr
),它们可以自动管理内存生命周期,极大减少内存泄漏的风险。
3. Lambda 表达式
是什么: 一种匿名函数对象,可以在代码中就地定义短小的函数,而无需正式声明一个函数。
如何理解: 它类似于JavaScript中的箭头函数。它捕获上下文变量、接受参数、并有一个函数体。它使得代码更简洁,尤其是在与STL算法配合时。
如何使用:
基本语法:
[capture] (parameters) -> return_type { function_body }
捕获列表
[capture]
是关键:[=]
:以值的方式捕获所有外部变量。[&]
:以引用的方式捕获所有外部变量。[a, &b]
:以值捕获a,以引用捕获b。
示例:与
std::sort
或std::for_each
配合使用。std::vector<int> vec = {4, 2, 5, 1}; std::sort(vec.begin(), vec.end(), [](int a, int b) { return a > b; }); // 降序排列
4. 面向对象:封装、继承、多态
是什么: 面向对象编程的三大核心特性。
如何理解与使用:
封装: 将数据(属性)和操作数据的方法(函数)绑定在一起,并隐藏内部实现细节,只暴露接口。通过
class
和访问控制符public
,private
,protected
实现。在您的项目中,每个模块的类设计都体现了封装思想。继承: 允许一个新类(派生类)继承另一个类(基类)的属性和方法,实现代码复用和层次化设计。如
class Dog : public Animal {}
。多态: 允许不同类的对象对同一消息做出不同的响应。通常通过基类的虚函数和指针/引用来实现。
class Shape { public:virtual void draw() = 0; // 纯虚函数,抽象基类 }; class Circle : public Shape { public:virtual void draw() override { /* 画一个圆 */ } }; // 多态的使用 Shape *shape = new Circle(); shape->draw(); // 调用的是 Circle::draw()
在您项目中的应用: QT的整个 widget 系统就是基于继承和多态。
QPushButton
继承自QWidget
,您可以重写paintEvent
等虚函数来实现自定义UI。
二、 内存管理
1. 堆栈机制
是什么: 程序运行时内存管理的两种基本方式。
如何理解:
栈: 由编译器自动分配和释放。存放局部变量、函数参数等。分配速度快,但空间有限,生命周期与函数作用域绑定。
堆: 由程序员手动分配和释放(
new/delete
或malloc/free
)。空间大,分配速度慢,生命周期由程序员控制,管理不当会导致内存泄漏或野指针。
如何使用: 小型、生命周期短的变量用栈。大型对象、需要动态控制生命周期的对象用堆(并尽量用智能指针管理)。
2. 手动内存管理
是什么: 使用
new
和delete
成对操作来在堆上分配和释放内存。如何理解: 谁申请,谁释放。忘记释放会导致内存泄漏;释放后再次使用会导致未定义行为。在复杂流程中,确保在每一个分支路径上都正确释放内存非常具有挑战性。
如何使用: 强烈建议在现代C++项目中避免直接使用
new/delete
。使用std::vector
,std::string
等容器以及std::unique_ptr
和std::shared_ptr
等智能指针来自动化内存管理。您在“性能优化”中提到的“内存池”是更高级的手动内存管理技术,用于特定性能敏感场景。
三、 QT 框架
1. 信号和槽
是什么: QT的核心机制,用于对象之间的通信。它是一种类型安全的“观察者模式”。
如何理解: 当某个对象(发送者)的状态发生变化时,它会发射一个信号。另一个对象(接收者)的槽函数可以对这种变化做出响应。它们通过
QObject::connect
函数连接。如何使用:
// 声明 class Sender : public QObject {Q_OBJECT signals:void valueChanged(int newValue); }; class Receiver : public QObject {Q_OBJECT public slots:void handleValueChange(int value) { ... } }; // 连接 Sender s; Receiver r; QObject::connect(&s, &Sender::valueChanged, &r, &Receiver::handleValueChange); // 触发 emit s.valueChanged(10); // 此后,r.handleValueChange(10) 会被自动调用
在您项目中的应用: 这是QT程序事件驱动的基石。按钮点击、定时器超时、网络数据到达等,都是通过信号和槽来通知和处理的。
2. 事件过滤器
是什么: 一种更高级的事件处理机制,允许一个对象监视并拦截发送给另一个对象的事件。
如何理解: 比如主窗口可以安装事件过滤器来监听所有子控件的事件(如鼠标点击、按键),并在事件到达目标控件之前先进行处理或过滤掉。
如何使用:
在监视者对象中重写
eventFilter(QObject *watched, QEvent *event)
方法。调用
watchedObject->installEventFilter(filterObject);
进行安装。
在您项目中的应用: 可用于实现全局快捷键、自定义鼠标行为、验证输入等。
3. 多线程编程
是什么: 使用
QThread
等类来并发执行任务,防止耗时操作阻塞主线程(UI线程)。如何理解: QT推荐使用工作线程模式,而非继承QThread。即将一个的工作对象(继承自
QObject
)移动到一个线程中,通过信号和槽与主线程通信。QThread *thread = new QThread; Worker *worker = new Worker; // Worker 是一个QObject worker->moveToThread(thread); // 关键步骤 // 连接信号槽:启动线程、开始工作、汇报进度、结束线程 connect(thread, &QThread::started, worker, &Worker::doWork); connect(worker, &Worker::resultReady, this, &MainWindow::handleResult); connect(worker, &Worker::finished, thread, &QThread::quit); connect(thread, &QThread::finished, thread, &QThread::deleteLater); thread->start();
在您项目中的应用: 您在“广告机系统”中明确提到了“使用QThread开发专用工作线程,处理网络IO和文件操作”,这正是该模式的典型应用。
四、 图像处理 (OpenCV)
1. 图像滤波(如高斯滤波)
是什么: 使用一个“核”在图像上滑动,计算邻域像素的加权平均值,用于去噪和平滑。
如何理解: 高斯滤波的权重服从高斯分布(正态分布),中心点权重最大,越远权重越小。能很好地消除高斯噪声,并保留更多的图像边缘信息 compared to mean filter。
如何使用:
cv::GaussianBlur(src, dst, Size(5,5), 0);
2. 边缘检测(如Canny)
是什么: 识别图像中亮度变化剧烈的点,这些点通常对应物体的边缘。
如何理解: Canny边缘检测是一个多阶段的算法(噪声去除->计算梯度->非极大值抑制->双阈值筛选),结果是干净、连续的边缘。
如何使用:
cv::Canny(src, edges, threshold1, threshold2);
3. 特征提取与匹配
是什么: 特征是图像中具有独特性的局部结构(如角点、斑块)。匹配是在不同图像中寻找相同特征的过程。
如何理解: 就像人的“痣”或“脸部轮廓”是特征。SIFT、SURF、ORB等算法可以提取这些特征并生成一个描述子向量。通过比较描述子向量的距离,可以判断两个特征是否匹配。
在您项目中的应用: 您在“纺织面料疵点检测”项目中,提取疵点的“特征向量”就是为了后续能够对疵点进行分类和识别。
五、 开发工具 & 其他
1. 版本控制 (Git/SVN)
是什么: 记录代码变更历史、协同开发的工具。
核心概念:
Git: 分布式。每个开发者都有完整的仓库克隆。常用命令:
clone
,add
,commit
,push
,pull
,branch
,merge
。SVN: 集中式。只有一个中央仓库。常用命令:
checkout
,update
,commit
。
如何理解: 代码的“时光机”。允许回退到任何历史版本,并行开发不同功能(分支),解决代码冲突,追踪谁在何时改了什麼。
2. 数据库 (MySQL/SQLite)
是什么: 结构化数据存储和管理系统。
核心概念与使用:
SQLite: 轻量级,嵌入式的数据库,整个库就是一个文件。非常适合桌面应用、移动应用(如您的QT终端程序)作为本地存储。
MySQL: 强大的客户端-服务器型数据库,支持高并发、大规模数据。适合作为Web应用或分布式系统(如您的广告机管理系统)的后端数据库。
CRUD: 增(INSERT)、删(DELETE)、改(UPDATE)、查(SELECT)是基本操作。
索引: 加速查询的数据结构,理解它对于“优化数据库查询性能”至关重要。
3. 网络协议 (TCP/UDP/HTTP/MQTT)
是什么: 设备之间通信的规则。
如何理解与使用:
TCP: 面向连接、可靠、有序的字节流传输。像打电话,需要建立连接,保证对方能听到。用于需要可靠性的场景(如文件传输、网页浏览)。
UDP: 无连接、不可靠的数据报传输。像发广播,不保证对方收到。用于实时性要求高、可容忍少量丢失的场景(如视频通话、游戏)。
HTTP: 基于TCP的应用层协议,是Web通信的基础(请求-响应模型)。
MQTT: 轻量级的发布-订阅消息协议,专为物联网设计。您在广告机项目中的核心贡献就是基于此协议。
理解发布-订阅: 设备(客户端)连接到代理服务器(如EMQX)。设备订阅它感兴趣的主题(如
device/001/temperature
)。另一个设备向这个主题发布消息。代理服务器负责将消息转发给所有订阅了该主题的设备。实现了发布者和订阅者的解耦。