C++ 在C+中定义纯虚信号有效吗+/Qt?
我正在创建一个抽象的基类,并在想我可能需要一个纯虚拟信号。但当我编译时,我得到了一个关于我定义的纯虚拟信号的警告:C++ 在C+中定义纯虚信号有效吗+/Qt?,c++,qt,abstract-class,signals-slots,C++,Qt,Abstract Class,Signals Slots,我正在创建一个抽象的基类,并在想我可能需要一个纯虚拟信号。但当我编译时,我得到了一个关于我定义的纯虚拟信号的警告: ../FILE1.h:27: Warning: Signals cannot be declared virtual ../FILE1.h:28: Warning: Signals cannot be declared virtual 在C++/Qt中定义纯虚拟信号有效吗?定义虚拟信号有效吗? 表示可以定义虚拟插槽,但不讨论信号。我似乎找不到关于纯虚拟信号的好信息。我认为拥有(纯
../FILE1.h:27: Warning: Signals cannot be declared virtual
../FILE1.h:28: Warning: Signals cannot be declared virtual
在C++/Qt中定义纯虚拟信号有效吗?定义虚拟信号有效吗?
表示可以定义虚拟插槽,但不讨论信号。我似乎找不到关于纯虚拟信号的好信息。我认为拥有(纯)虚拟信号毫无意义。提供给Qt的
signals
宏仅扩展到protected
,因此您声明的所有信号实际上都是受保护方法的声明。由moc生成的代码将提供这些功能的实现。- 信号从来没有实现[1](即,在.h文件中定义信号,然后在.cpp中没有实现)李>
- 声明纯虚函数的主要目的是强制继承类提供实现
对于抽象基类,我认为以下内容是正确的: 当只声明函数为“virtual”时,仍会发出警告。为了避免任何警告,我认为解决方案是不使用任何“virtual”或“pure virtual”限定信号,然后继承类将不会声明任何信号,但仍然可以发出基类中定义的信号
[1] 当我说“信号从来没有实现”时,我的意思是实现类的人没有提供实现。据我所知,幕后Qt的moc在moc_FILE1.cpp中提供了一个实现。有一个解决方案可以创建纯虚拟功能,将给定的插槽连接到信号,反之亦然。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);
}
警告是MOC报告的,而不是C++编译器的,除了在抽象接口的特定情况下是有效的。 虚拟信号的唯一有效用途是在声明不是从
QObject
派生的抽象接口时。这种方法没有错。主运行中心尽力提供帮助,因为在大多数情况下,虚拟信号是错误的
即使如此,不获取警告的简单解决方法是跳过界面中的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"
//https://github.com/KubaO/stackoverflown/tree/master/questions/virtual-slot-10029130
#包括
类I接口{
公众:
//无信号:部分,因为它不是QoObject!
虚空巴克()=0;//一个信号
};
ADog类:公共QObject、公共IDogInterface{
Q_对象
公众:
Q_SIGNAL void barks()override;//实现由moc生成
};
类监视器:公共QObject{
Q_对象
int m_计数{};
Q_插槽void onBark(){m_count++}
公众:
int count()常量{返回m_count;}
无效监视器吠叫(IDogInterface*狗){
QObject*dogObject=动态施法(狗);
if(dogObject){
连接(dogObject,信号(barks()),插槽(onBark());
}否则{
qWarning()虚拟信号有意义的两种情况:
派生类可能希望通过跳过基类实现来选择性地阻止信号的发送
派生类可能希望将其用作事件机制,并在将信号发送给侦听器之前或之后对其作出反应
这两种情况也可以用其他不太面向对象的方式来处理。为什么您认为要使信号虚拟?给出了一种不同的方法,使用CRTP和通用基类。它允许轻松分解多个QObject
派生类共有的代码,即使它们派生自不同的基类(当然,它们不需要直接从QObject
派生)是一个更好的解决方案。