您的位置:首页 > 编程语言 > Qt开发

利用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
即可。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息