一句话:Qt 类本质就是 C++ 的类,只是 Qt 框架扩展了一套【QObject 对象模型】 。 普通 C++ 类:只封装变量、成员函数; 继承 QObject 的 Qt 类:除了普通 C++ 能力,额外拥有【信号槽、对象树自动内存管理、元对象系统】三大核心能力Qt

一、最核心根类:QObject(重中之重)
QObject = Qt 世界所有对象的祖宗基类 几乎所有控件、窗口、定时器、线程类,都是它的子类(直接继承 / 间接继承)。
注意区分两个概念:
- 继承关系(父类 / 子类):C++ 的类继承,QWidget 继承 QObject;
- 对象树父子 (parent) :对象实例之间的归属,用来自动管理内存,不是 C++ 继承!
✅ QObject 带来 3 个核心功能:
- 信号与槽(对象通信):对象之间不用硬调用函数,通过信号槽收发消息(按钮点击就是典型信号)
- 对象树自动内存管理(parent 机制) new 对象时传入
this作为父对象;父对象销毁,自动删除全部子对象,不用手动 delete,减少内存泄漏 - 元对象系统(moc 工具):运行时知道类名字、函数,实现 Q_OBJECT 宏的能力
⚠️ 例外:
QString、QList、QColor这类值类型类 ,不继承 QObject,和普通 C++ 的 string、vector 用法接近,不能写 Q_OBJECT、不能用信号槽。
二、可视化窗口核心类:QWidget(所有界面控件的基类)

QWidget 继承自 QObject + QPaintDevice(绘图设备) 只要能在屏幕上显示出来的东西,全部是 QWidget 子类:
- QMainWindow:主窗口(带菜单栏、状态栏,Qt 新建项目默认的窗口类)
- QDialog:弹窗对话框(提示框、文件选择框)
- QPushButton:按钮
- QLabel:文本 / 图片标签
- QLineEdit:单行输入框
简单理解:QObject 负责逻辑通信、内存管理 ;QWidget 额外增加界面绘制、鼠标键盘事件。
三、写一个自己的 Qt 类(完整示例,逐行解释)
新建头文件 myclass.h
cpp
#ifndef MYCLASS_H
#define MYCLASS_H
#include <QObject>
// 自定义Qt类:继承QObject
class MyClass : public QObject
{
// 开启元对象系统,必须写,才能用信号槽
Q_OBJECT
public:
// 构造函数,explicit防止隐式转换;parent父对象默认nullptr
explicit MyClass(QObject *parent = nullptr);
// 普通成员函数,用来发射信号
void testSend();
// 信号:对外发出通知,只声明,不写函数体
signals:
void msgSignal(QString text);
// 槽函数:接收信号,执行业务
public:
void recvSlot(QString text);
};
#endif // MYCLASS_H
cpp 文件 myclass.cpp
cpp
#include "myclass.h"
#include <QDebug>
// 构造函数:初始化列表调用父类QObject构造,传入parent
MyClass::MyClass(QObject *parent)
: QObject(parent)
{
}
void MyClass::testSend()
{
// emit发射信号
emit msgSignal("Hello Qt类!");
}
// 槽函数实现,收到信号后打印
void MyClass::recvSlot(QString text)
{
qDebug() << "槽收到消息:" << text;
}
main.cpp
cpp
#include <QCoreApplication>
#include "myclass.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyClass obj1; // 信号发送对象
MyClass obj2; // 接收对象
// connect连接信号槽
connect(&obj1, &MyClass::msgSignal, &obj2, &MyClass::recvSlot);
obj1.testSend(); // 调用函数,触发emit发射信号
return a.exec();
}
运行输出:槽收到消息:"Hello Qt类!"
四、对象树(parent 机制,新手最容易混淆)
cpp
// 创建按钮,父对象是当前窗口this
QPushButton *btn = new QPushButton("测试按钮", this);
图解逻辑:
- btn 的 parent = this(当前窗口对象)
- 窗口对象会把 btn 加入自己的 children 子对象列表
- 关闭窗口,窗口对象销毁,自动把 btn delete,不用手动释放内存
❗重点:parent 是对象实例之间的归属关系,不是类的继承! 类比: 类的继承:人 → 学生(模板的继承) 对象树 parent:家长 → 孩子(实例的归属,家长消失孩子跟着销毁)
五、Qt 类 和 普通 C++ 类对比表
| 对比项 | 普通 C++ 类 | 继承 QObject 的 Qt 类 |
|---|---|---|
| 继承 | 默认无父类 | 必须继承 QObject/QWidget 等 |
| Q_OBJECT | 不能写 | 需要写,开启元对象系统 |
| 信号槽 | 不支持 | 支持,emit+connect |
| 内存管理 | new 之后必须手动 delete | 设置 parent,父对象自动回收子对象 |
| 拷贝赋值 | 支持 | ❌禁止拷贝,不能objA=objB |
| 运行时识别 | RTTI 才可以 | 自带元对象,直接获取类名 |
六、新手高频踩坑
- 写 Q_OBJECT,忘记执行 qmake ,编译报
undefined reference to vtable虚表错误 解决:菜单栏【构建】→【Run qmake】再重新构建项目 - QObject 子类不能拷贝 ,不能写
MyClass a = b;,只能用指针 - UI 控件(QPushButton、QLabel)属于 QWidget,只能在主线程操作,子线程不能直接修改界面
QString/QList这些值类型不是 QObject 子类,不能写 Q_OBJECT,没有 parent,用法和 std::string 类似