Qt 是否可以使用“发送”从派生对象的基类发出信号;这";
我不太清楚如何表述我的问题,我希望这更清楚。我想要一个基类,看起来像这样:Qt 是否可以使用“发送”从派生对象的基类发出信号;这";,qt,inheritance,signals-slots,Qt,Inheritance,Signals Slots,我不太清楚如何表述我的问题,我希望这更清楚。我想要一个基类,看起来像这样: class Base : public QObject { Q_OBJECT void doSomething() { emit test(this); } virtual void doSomethingElse() = 0; signals: void test(Base*); } 然后在派生类中执行以下操作: class Derived : public Base {
class Base : public QObject {
Q_OBJECT
void doSomething() { emit test(this); }
virtual void doSomethingElse() = 0;
signals:
void test(Base*);
}
然后在派生类中执行以下操作:
class Derived : public Base {
void doSomethingElse() { emit test(this); }
}
如果我现在听这个对象的信号,我听的是test(派生*)还是/和test(基本*)?你不应该把发送者作为信号的参数。只需使用
QObject::sender()
即可获取发送信号的QObject
例如:
然后在插槽中:
void Listener::someObject_test() {
QObject* sender = QObject::sender();
// or:
Derived* sender = (Derived*)QObject::sender();
}
moc在编译时根据您在使用
Q_对象的类中声明插槽和信号的方式生成插槽和信号的列表。
此列表是字符串列表,因此如果声明:
signals:
void test(Base*);
列表中的项目是字符串“test(Base*)”
(您可以在输出目录中文件moc\u YourClass.cpp
的变量qt\u meta\u YourClass
中看到该列表)。
宏SIGNAL
和SLOT
也返回字符串,connect()
将其规范化,使其格式与moc生成列表中的格式相同,并将其与该列表中的字符串进行比较
派生类时,字符串没有更改,因此您仍然必须使用信号(test(Base*))
由于派生类没有自己的信号,您将侦听测试(Base*)。我以为文档是针对发送方的()?我使用了多次,从未遇到任何问题。文档声明“此函数违反了面向对象的模块化原则”。如果您提供对象作为信号的参数,它也将违反相同的原则。有时需要知道信号来自何处,在这种情况下,使用QObject::sender()
是最简单的方法。sender()
不是免费的,它锁定互斥锁并执行列表查找。如果将对象作为信号的参数传递,从语义上讲,它表明该对象是消息的一部分,您不必使用强制转换来使用对象,并且当信号和插槽属于不同的线程时,它也会工作,而不像发送方()
。作为奖励,您甚至可以使用非发送方的对象作为参数发出信号。@alexidm,谢天谢地,Qt并不是围绕着每个信号作为参数发送发送方的概念设计的。否则,每次重写Qt类时,我都必须重写(并复制)每个发送信号的方法。此外,您必须始终强制转换从QObject::sender()
获得的对象,因为它将始终为您提供一个QObject
(除非您需要一个QObject,这是很少见的)。最后,我不相信列表查找会那么慢。您主要需要用户生成的事件的信号,这些事件并不那么频繁。对于任何更频繁的操作,可能会有一些优化。也许发送发送方作为参数是一种优化,也许有更好的方法。。。但无论如何,这是一个临界情况,取决于应用程序。你能具体说明“侦听”的意思吗?在这种情况下,很多事情都取决于它,例如侦听-将发送方作为插槽或?通过“connect(objectInMyExample,SIGNAL(test(Base*/Derived*))”、someOtherObject、SLOT(handleObject(Base*/Derived*))来连接它,这样在handleObject(Base*)中它将处理Base和handleObject(Derived*))它会侦听派生的。我应该使信号虚拟化还是更好地从BaseCase-派生类中抛出而不是使用发送器和从QOBject到基类/派生类的转换?技术上是的,即使MOC会给您警告。并且C++不支持协变或逆变参数,所以<代码>测试(BASE *)
和测试(派生*)
将是不相关的。您仍然可以通过执行依赖于对象本身的Base*
或派生*
的部分来避免强制转换,方法是通过虚拟函数或使用访问者模式。hm。因此,如果我的理解正确,如果我在基类中的函数是虚拟的,那么我是否获得指向基*,我仍然会得到虚拟函数等。
signals:
void test(Base*);