利用Qt进行接口间通信

简介: 简述 接口的作用,就是提供一个与其他系统交互的方法。其他系统无需(也无法)了解内部的具体细节,只能通过对外提供的接口来与进行通信。

简述

接口的作用,就是提供一个与其他系统交互的方法。其他系统无需(也无法)了解内部的具体细节,只能通过对外提供的接口来与进行通信。

纯虚函数(包括槽)很容易理解,那么信号呢?

在 Qt 中,定义一个纯虚信号有效吗?

的确,这个话题非常有意思。。。通常,我们会定义一些纯虚的槽函数,但关于纯虚信号这个话题讨论的比较少!那么,信号可不可以是纯虚的呢?

版权所有:一去丶二三里,转载请注明出处:http://blog.csdn.net/liang19890820

一些设想

关于信号和纯虚,我们知道:

  • 信号永远不会有实现(也就是说,在 .h 中定义了信号,在 .cpp 中不需要实现)
  • 声明一个纯虚函数的主要目的,是强制继承的类提供一个实现。

信号没有实现,如果将其声明为纯虚的,需要继承的类来提供一个实现,这与“信号没有实现”直接冲突。就好比让一个人同时出现在两个地方,这是不可能的。因此,似乎声明一个纯虚信号是一个错误。

在编写完一个接口时,为了能使用 Qt 的信号槽特性,很多人可能会写出类似下面的代码:

这里写图片描述

很遗憾,Qt 发出了警告:

warning: Signals cannot be declared virtual

那么,如何解决这个问题呢?

解决方案

下面,列出三种解决方案:

  • 派生自 QObject,信号不使用 virtual
  • 将“信号”定义为一个纯虚函数
  • 在接口中定义信号槽的连接方式

测试效果如下:

这里写图片描述

派生自 QObject,信号不使用 virtual

不让用 virtual,好吧,那就不用了,这算是最简单的解决方式!

#ifndef CLOCK_H
#define CLOCK_H

#include <QObject>

class IClock : public QObject
{
    Q_OBJECT

public:
    ~IClock() {}
    virtual void doSomething() = 0;

signals:
    void alarm();
};

#endif // CLOCK_H

具体的实现也与信号无关了,只需要实现其他接口即可:

#ifndef DIGITAL_CLOCK_H
#define DIGITAL_CLOCK_H

#include "clock.h"
#include <QObject>
#include <QtDebug>

class DigitalClock : public IClock
{
    Q_OBJECT

public:
    DigitalClock() {}

    void doSomething() Q_DECL_OVERRIDE {
        qDebug() << "Do something...";
    }
};

#endif // DIGITAL_CLOCK_H

但是这种方式并不算理想,因为一般来说,接口是一个简单的 C++ 类,不需要派生自 QObject

将“信号”定义为一个纯虚函数

将“信号”定义为一个纯虚函数:

#ifndef CLOCK_H
#define CLOCK_H

class IClock
{
public:
    ~IClock() {}
    virtual void doSomething() = 0;

    // 不是一个信号(但可以当做信号来用),因为 IClock 不是 QObject
    virtual void alarm() = 0;
};

#endif // CLOCK_H

注意: 对于 IClock 来说,alarm() 只是一个纯虚函数,并不是一个“信号”(但可以当做信号来用),因为 IClock 不是 QObject

由于需要信号支持,所以具体实现需要派生自 QObject。此外,还需要将 alarm() 定义为 signals

#ifndef DIGITAL_CLOCK_H
#define DIGITAL_CLOCK_H

#include "clock.h"
#include <QObject>
#include <QtDebug>

class DigitalClock : public QObject, public IClock
{
    Q_OBJECT

public:
    DigitalClock() {}

    void doSomething() Q_DECL_OVERRIDE {
        qDebug() << "Do something...";
    }

signals:
    // 实现由 moc 来完成
    void alarm() Q_DECL_OVERRIDE;
};

#endif // DIGITAL_CLOCK_H

这时,alarm() 的具体的实现在内部是由 moc 来完成的。

为了测试是否有效,再定义一个类 - monitor.h

#ifndef MONITOR_H
#define MONITOR_H

#include <QObject>
#include <QtDebug>
#include "clock.h"

class Monitor : public QObject
{
    Q_OBJECT

private slots:
    void onAlarm() {
        qDebug() << "Get up";
    }

public:
    void monitorAlarm(IClock *clock) {
        QObject *clockObject = dynamic_cast<QObject *>(clock);
        if (clockObject) {
            connect(clockObject, SIGNAL(alarm()), this, SLOT(onAlarm()));
        } else {
            qWarning() << "cannot monitor Alarm";
        }
    }
};

#endif // MONITOR_H

注意: 连接信号时,需要将其转换为 QObject

main.cpp 中进行测试:

#include <QCoreApplication>
#include "digital_clock.h"
#include "monitor.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    DigitalClock clock;
    Monitor monitor;
    monitor.monitorAlarm(&clock);
    emit clock.alarm();

    return a.exec();
}

在接口中定义信号槽的连接方式

除了上述方式之外,还可以在接口中定义信号槽的连接方式。

首先,定义一个连接信号槽的接口 - connectToAlarm()

#ifndef CLOCK_H
#define CLOCK_H

#include <QObject>

class IClock
{
public:
    ~IClock() {}
    virtual void doSomething() = 0;
    virtual bool connectToAlarm(QObject *receiver, const char *pszSlot, bool isConnect) const = 0;
};

#endif // CLOCK_H

然后,在派生类中实现信号槽的具体连接:

#ifndef DIGITAL_CLOCK_H
#define DIGITAL_CLOCK_H

#include "clock.h"
#include <QObject>
#include <QtDebug>

class DigitalClock : public QObject, public IClock
{
    Q_OBJECT

public:
    DigitalClock() {}

    void doSomething() Q_DECL_OVERRIDE {
        qDebug() << "Do something...";
    }

    bool connectToAlarm(QObject *receiver, const char *pszSlot, bool isConnect) const Q_DECL_OVERRIDE {
        if (isConnect)
            return connect(this, SIGNAL(alarm()), receiver, pszSlot);
        return disconnect(this, SIGNAL(alarm()), receiver, pszSlot);
    }

signals:
    void alarm();
};

#endif // DIGITAL_CLOCK_H

这样以来,连接方式就变得简单多了。

#ifndef MONITOR_H
#define MONITOR_H

#include <QObject>
#include <QtDebug>
#include "clock.h"

class Monitor : public QObject
{
    Q_OBJECT

public slots:
    void onAlarm() {
        qDebug() << "Get up";
    }

public:
    void monitorAlarm(IClock *clock) {
        bool isConnect = clock->connectToAlarm(this, SLOT(onAlarm()), true);
        if (isConnect) {
            qWarning() << "connectToAlarm";
        } else {
            qWarning() << "cannot monitor Alarm";
        }
    }
};

#endif // MONITOR_H

除了信号槽之外,Qt 还可以通过事件机制(sendEvent()postEvent())来实现接口之间的通信。正如上所示,只要通过接口来获得 QObject 即可。

目录
相关文章
|
3月前
|
运维 监控 网络协议
QT实现TCP通信:从基础到高级的全面解析
QT实现TCP通信:从基础到高级的全面解析
211 0
|
5月前
|
存储 C语言 Windows
音视频使用qt测试ffmpeg接口时无法运行
音视频使用qt测试ffmpeg接口时无法运行
52 0
|
2月前
|
存储 C++ 网络架构
C++ Qt开发:QUdpSocket实现组播通信
Qt教程:使用`QUdpSocket`实现UDP组播通信。通过设置套接字选项、绑定端口、加入和离开组播组,以及发送和接收数据报,简化跨平台窗体应用开发。关键函数包括`setSocketOption`设置多播TTL,`bind`绑定地址和端口,`joinMulticastGroup`加入组播,`leaveMulticastGroup`退出,`writeDatagram`发送,和`readDatagram`接收数据报。
30 1
C++ Qt开发:QUdpSocket实现组播通信
|
2月前
|
安全 Linux 网络安全
Qt SSL/TLS 安全通信类:构建安全网络应用的关键组件
Qt SSL/TLS 安全通信类:构建安全网络应用的关键组件
69 0
|
2月前
【QFileDialog接口大全】 Qt5 QString类使用示例
【QFileDialog接口大全】 Qt5 QString类使用示例
13 1
|
2月前
|
存储 API C++
【 QString接口大全】 Qt QString类使用示例
【 QString接口大全】 Qt QString类使用示例
27 1
|
2月前
|
缓存 网络安全 调度
C++ Qt开发:QNetworkAccessManager网络接口组件
Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍如何运用`QNetworkAccessManager`组件实现Web网页访问。QNetworkAccessManager是Qt网络模块中的关键类,用于管理网络访问和请求。作为一个网络请求的调度中心,它为Qt应用程序提供了发送和接收各种类型的网络请求的能力,包括常见的GET、POST、PUT、DELETE等。这个模块的核心功能在于通过处理`QNetworkReply`和`QNetworkRequest`来实现
26 0
C++ Qt开发:QNetworkAccessManager网络接口组件
|
2月前
|
监控 C++ 索引
C++ Qt开发:QNetworkInterface网络接口组件
在Qt网络编程中,`QNetworkInterface`是一个强大的类,提供了获取本地网络接口信息的能力。通过`QNetworkInterface`,可以轻松地获取有关网络接口的信息,包括接口的名称、硬件地址、IP地址和子网掩码等。这个类对于需要获取本地网络环境信息的应用程序特别有用,例如网络配置工具、网络监控程序等。`QNetworkInterface`通过提供一致而易于使用的接口,使得网络编程中的任务更加简便和可靠。
26 4
C++ Qt开发:QNetworkInterface网络接口组件
|
7月前
|
计算机视觉
[笔记]OpenCV+FFmpeg+Qt实现视频编辑器之OpenCV视频lO接口
[笔记]OpenCV+FFmpeg+Qt实现视频编辑器之OpenCV视频lO接口
105 0
|
7月前
|
Linux
linux系统中使用QT实现CAN通信的方法
linux系统中使用QT实现CAN通信的方法
215 0