利用Qt进行接口间通信
2017-09-29 19:56
274 查看
简述
接口的作用,就是提供一个与其他系统交互的方法。其他系统无需(也无法)了解内部的具体细节,只能通过对外提供的接口来与进行通信。纯虚函数(包括槽)很容易理解,那么信号呢?
在 Qt 中,定义一个纯虚信号有效吗?
的确,这个话题非常有意思。。。通常,我们会定义一些纯虚的槽函数,但关于纯虚信号这个话题讨论的比较少!那么,信号可不可以是纯虚的呢?
简述
一些设想
解决方案
派生自 QObject信号不使用 virtual
将信号定义为一个纯虚函数
在接口中定义信号槽的连接方式
版权所有:一去丶二三里,转载请注明出处: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即可。
相关文章推荐
- 利用Qt进行接口间通信
- Activity与Activity利用接口进行数据通信
- java netty socket库和自定义C#socket库利用protobuf进行通信完整实例
- java利用接口和适配器进行完全解耦
- java netty socket库和自定义C#socket库利用protobuf进行通信完整实例
- 利用.Text提供的Web服务接口进行开发出现的问题。
- android利用handler进行内部通信
- 【方法】STM32F407单片机SDIO接口上插入多张SD卡并进行通信
- 在LiveCode中利用socket进行通信(1)--入门介绍
- QT小程序:利用QGraphicsScene和QGraphicsView进行显示操作
- 利用UDP进行两台主机进行通信
- 利用三层交换进行VLAN间的通信
- c#和java语言利用webservice进行通信浅析
- 利用Qt进行FTP网络编程
- 父进程利用fork()函数创建子进程并且利用shared_memory进行通信的实例
- 【Caffe的C++接口使用说明(三)】Ubuntu14.04下Caffe利用训练好的模型进行分类的C++接口使用说明(三)
- JAVA利用HttpClient进行HTTPS接口调用的方法
- Archlinux中利用QtDesigner进行Ruby编程
- 利用Qt进行FTP网络编程
- 利用博创2410s实验箱进行qt开发经验总结 (原创)