核心结论(先看 一表 + 三条)
 

概念 一句话理解
class 把变量+函数打包,比 struct 多了函数和访问控制
:: "属于哪个类",左边类名右边函数名
explicit 防呆锁,禁止编译器偷偷转型
构造函数 Client::Client 必须和类名一样,创建对象时自动调
初始化列表 : QObject(parent) 在 {} 之前初始化父类和成员
this 指向当前对象自己
&类名::函数名 取类内·成员函数地址
connect((指定发送者)发,(什么信号与函数绑定)信号,
    接收者, 槽(接收者调用的函数))
注册回调——信号来了自动调槽函数
signals: 类内只需声明,Qt 自动生成实现
slots: 普通函数,但能被信号触发
m_ 前缀 成员变量命名习惯,一看就知道是 member
new QTcpSocket(this) 创建对象(套接字) + 指定父对象(当前函数自己),Qt 自动管内存
  1. :类型定义(编译时的蓝图),不占运行内存。

  2. 对象:类的实例(变量),占内存。

  3. 函数:可执行代码,包括普通函数、构造/析构、成员函数、信号、槽。

    • 构造函数/析构函数也是函数,不是对象。

    • explicit 是修饰构造函数的关键字(防止被改为对象),关键点有讲解。


class 的完整使用流程(5 步)

步骤 文件/动作 本质
1. 声明类 client.h 写 class Client { ... }; 定义类型成员(变量+函数)
2. 实现成员函数 client.cpp 写 Client::connectToServer(...){...} 填充函数体
3. 创建对象 Client *c = new Client(this); 或 Client c; 分配内存 + 调用构造函数
4. 调用成员函数 c->sendCommand("scan"); 执行代码,操作对象内部数据
5. 连接信号槽 connect(c, &Client::tagReceived, this, &MyWidget::handleTag); 建立对象间的松耦合通信

关键点

  • new Client(this):堆分配 + 自动调用构造函数,显示声明 客户端带可选父类参数 ,用于创建对象
        explicit Client(QObject *parent = nullptr);。

  • Client c; :栈分配 + 自动调用构造函数(作用域结束调析构函数 ~ 开头)。

  • 构造函数可重载,explicit 禁止隐式转换(例如禁止 Client c = "str";)。

  • 重载:同名函数(构造)不同参数,编译器自动匹配。


多继承:C++ 允许,但 Qt 的 QObject 有限制

1. 什么是「继承」?

继承就是:让一个类(子类),直接拿到另一个类(父类)的所有功能和特性,不用自己再写一遍

  • 你创建一个 QObject 父类(Qt 里所有支持信号槽的类的 “祖宗”)
  • 再写一个 MyDevice : public QObject
  • 那么 MyDevice继承了 QObject 的所有功能(比如信号槽机制、父子对象内存管理),还能加自己的代码。

2. 用图里的代码讲

cpp

class MyDevice : public QObject {
    Q_OBJECT
    QTcpSocket *socket;
    QTimer *timer;
};

这里:

  • MyDevice : public QObject
    • MyDevice子类
    • QObject父类
    • : public QObject 就是继承关系

效果

  • MyDevice 自动拥有了 QObject 的信号槽、事件循环、父子对象管理等所有能力
  • 它自己又加了 sockettimer 两个成员变量,扩展了自己的功能

3. 为什么不能同时继承两个 QObject 子类?

这就是你图里说的 “章程冲突”:

  • QObject 是所有 Qt 信号槽类的基类,里面有一套自己的元数据(Q_OBJECT 宏生成的)
  • 如果你写 class MyDevice : public QTcpSocket, public QTimer
    • 这两个父类都继承自 QObject
    • 就会让 MyDevice 里出现两套 QObject 的元数据
    • 编译器不知道该用哪一套,直接报错(就是所谓的 “菱形继承 / 元数据冲突”)

4. 图里的解决方案,怎么理解?

选一个当 “主公司”(继承),另一个当 “外包团队”(成员变量):

  • MyDevice 只继承 QObject(主公司,只留一套元数据)
  • QTcpSocketQTimer 作为成员变量(外包团队,各自用自己的元数据,互不冲突)

5. 一句话记住

  • 继承:就是 “我是你,我有你的所有东西”
  • 一个类只能继承一个 QObject 子类,否则会有两套信号槽元数据冲突
  • 要多个 Qt 功能,就继承一个,其他当成员变量

C++ 原生多继承(任意多个基类)

cpp

class A { int a; };
class B { int b; };
class C : public A, public B { };   // OK

Qt 中的限制

一个类不能同时继承两个直接或间接派生自 QObject 的类
原因:QObject 的元对象系统(moc)只支持单条继承链。多 QObject 基类会导致元数据冲突。

cpp

class X : public QObject { Q_OBJECT; };
class Y : public QObject { Q_OBJECT; };
class Z : public X, public Y { Q_OBJECT; };   // 错误!moc 无法处理

正确做法

在 Qt 里,关于继承的铁律只有一条:

一个类只能继承 1 个带 Q_OBJECT 的类(也就是 QObject 及其子类,比如 QTcpSocketQTimer),否则信号槽的元数据会冲突报错。

但有两种完全合法的方式,拿到多个类的功能:

  1. 继承一个 QObject + 多个普通 C++ 类(普通类无 Q_OBJECT

    cpp

    class Helper { public: void calc(); };
    class Worker : public QObject, public Helper { Q_OBJECT; };   // OK
  2. 组合:如果需要两个 QObject 子类的功能,用成员变量

    cpp

    // 普通C++类:不带Q_OBJECT,只是做计算用
    class Helper {
    public:
        void calc() {
            // 这里可以写你的业务逻辑
            int result = 1 + 1;
        }
    };
    
    // Qt类:继承QObject + 普通类Helper
    class Worker : public QObject, public Helper {
        Q_OBJECT // 只能有一个Q_OBJECT宏
    public:
        Worker(QObject *parent = nullptr) : QObject(parent) {}
    };

为什么这个写法合法?

  • Worker 只继承了一个Q_OBJECTQObject
  • Helper 是普通 C++ 类,没有信号槽元数据,所以不会冲突

反面教材(千万不要这么写!)

很多新手会犯的错,直接继承两个 QObject 子类

cpp

// 错误写法!会编译报错!
class MyDevice : public QTcpSocket, public QTimer {
    Q_OBJECT // 这里会出现两套元数据,冲突!
};

代码里的重点(真正需要记住的)

  • explicit RfidClient(QObject *parent = nullptr);
    → 构造函数声明,explicit 防止 RfidClient c = someQObject; 这种隐式构造。

  • RfidClient client;
    → 对象(栈上),自动调用构造函数。

  • client.connect();
    → 调用成员函数,操作 client 这个对象。

  • 信号 tagReceived(QString epc, QString tid);
    → 特殊函数声明(moc 生成实现),不返回,可被 emit 触发。

  • 槽函数 onReadyRead();
    → 普通成员函数,可被信号自动调用。

  • 多继承限制:如果一个类已经继承了 QObject(如 RfidClient),就不能再继承另一个 QObject 子类。


一句话最终总结 + 两种方案

类是类型,对象是变量,函数是动作;构造析构也是函数;C++ 允许多继承,但 QObject 子类只能单继承 QObject,其余用组合。

方案 适用场景 核心思路
继承 1 个 QObject + 多个普通类 你的普通类只是工具类,不需要信号槽 只留一套 Qt 元数据,其他类当 “附加功能”
组合(成员变量) 需要多个 Qt 类的信号槽功能 只继承 1 个 QObject,其他 Qt 类作为成员变量

更多推荐