我正在制作一个抽象基类,并且认为我可能想要一个纯粹的虚拟信号。但是当我编译时,我得到了我已经定义的纯虚拟信号的警告:
../FILE1.h:27: Warning: Signals cannot be declared virtual
../FILE1.h:28: Warning: Signals cannot be declared virtual
在C ++ / Qt中定义纯虚拟信号是否有效?定义虚拟信号是否有效?
Qt's signal and slot documentation page表示您可以定义虚拟插槽,但不会谈论信号。我似乎无法找到关于纯虚拟信号的好信息。
答案 0 :(得分:9)
鉴于以上两个陈述,我的想法是:
信号没有实现,但声明纯虚拟将需要继承类提供实现......这与“信号没有实现”直接冲突。这就像是要求某人同时在两个地方,这是不可能的。
总而言之,似乎宣称“纯虚拟”“信号”应该是错误,因此无效。
在抽象基类的情况下,我认为这是正确的:
当一个人宣称该功能只是“虚拟”时,它仍会发出警告。为了避免任何警告,我认为解决方案是不使用任何“虚拟”或“纯虚拟”限定信号,然后继承类不会声明任何信号,但仍然可以发出基类中定义的信号。
[1]当我说“信号没有实现”时,我的意思是实现该类的人不提供实现。据我所知,在场景背后,Qt的moc在moc_FILE1.cpp中提供了一个实现。
答案 1 :(得分:5)
警告由moc报告,而不是由C ++编译器报告,除了抽象接口的特定情况外,它是有效的。
虚拟信号的唯一有效用途是在声明不能从QObject
派生的抽象接口时,detailed in this excellent answer。这种方法没有错。 Moc试图提供帮助,因为在大多数情况下,虚拟信号是错误的。
即便如此, not 获取警告的简单解决方法是跳过界面中的signals:
关键字。这是完全没必要的,因为界面并非来自QObject
,因此根本不应该由moc处理:
// https://github.com/KubaO/stackoverflown/tree/master/questions/virtual-slot-10029130
#include <QtCore>
class IDogInterface {
public:
// no signals: section since it's not a QObject!
virtual void barks() = 0; // a signal
};
class ADog : public QObject, public IDogInterface {
Q_OBJECT
public:
Q_SIGNAL void barks() override; // implementation is generated by moc
};
class Monitor : public QObject {
Q_OBJECT
int m_count{};
Q_SLOT void onBark() { m_count++; }
public:
int count() const { return m_count; }
void monitorBarks(IDogInterface * dog) {
QObject * dogObject = dynamic_cast<QObject*>(dog);
if (dogObject) {
connect(dogObject, SIGNAL(barks()), SLOT(onBark()));
} else {
qWarning() << "cannot monitor barking on dog instance" << (void*)dog;
}
}
};
int main() {
ADog dog;
Monitor monitor;
monitor.monitorBarks(&dog);
emit dog.barks();
Q_ASSERT(monitor.count() == 1);
}
#include "main.moc"
答案 2 :(得分:2)
我认为拥有(纯)虚拟信号毫无意义。提供给Qt的signals
宏只是扩展为protected
,因此您声明的所有信号实际上都是受保护方法的声明。 moc
生成的代码将提供这些函数的实现。
答案 3 :(得分:0)
有一种创建纯虚函数的解决方案,它将给定的插槽连接到信号,反之亦然。 e.g:
class IBaseInterface
{
public:
virtual bool connectToSignal1(QObject* pReceiver, const char* pszSlot, bool bConnect) const = 0;
};
class CDerived : public QObject, public IBaseInterface
{
Q_OBJECT
public:
virtual bool connectToSignal1(QObject* pReceiver, const char* pszSlot, bool bConnect) const;
signals:
void signal1(const QString& msg);
};
bool CDerived::connectToSignal1(QObject* pReceiver, const char* pszSlot, bool bConnect) const
{
if(bConnect)
return connect(this, SIGNAL(signal1(QString)), pReciever, pszSlot);
return disconnect(this, SIGNAL(signal1(QString)), pReciever, pszSlot);
}
进一步在客户端代码中可以输入:
class CSomeClass : public QObject
{
Q_OBJECT
protected /*or public, or private*/ slots:
void someSlot(const QString& msg);
};
void CSomeClass::somefunction()
{
IBaseInterface* p = new CDerived;
if (!p->connectToSignal1(this, SLOT(someSlot(QString)), true))
QMessageBox::warning(this, tr("Warning"), tr("Cannot connect ...."), QMessageBox::Ok);
}
答案 4 :(得分:0)
虚拟信号有意义的两种情况:
这两种方案也可以用其他少OOP方式处理。