是否可以使用“this”从派生对象的基类发出信号
Posted
技术标签:
【中文标题】是否可以使用“this”从派生对象的基类发出信号【英文标题】:Is it possible to emit a signal from the baseclass of a derived object using "this" 【发布时间】:2012-03-22 02:27:21 【问题描述】:不太清楚如何提出我的问题,我希望这更清楚。我想要一个看起来像这样的基类:
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(Derived*) 还是/和 test(Base*)?
【问题讨论】:
你能具体说明“听”的意思吗? 通过 "connect(objectInMyExample, SIGNAL(test(Base*/Derived*)), someOtherObject, SLOT(handleObject(Base*/Derived*))) 连接它 好的,所以在 handleObject(Base*) 中它将处理 Base 而在 handlObject(Derived*) 中它将监听 Derived。 【参考方案1】:moc 在编译时根据您在使用Q_OBJECT
宏的类中声明它们的方式生成插槽和信号的列表。
这个列表是一个字符串列表,所以如果你声明:
signals:
void test(Base*);
列表中的项目将是字符串"test(Base*)"
(您可以在输出目录中文件moc_yourclass.cpp
的变量qt_meta_YourClass
中看到该列表)。
SIGNAL
和 SLOT
宏也返回字符串,connect()
将它们规范化,使它们的格式类似于 moc 生成列表中的格式,并将它们与该列表中的进行比较。
派生类的时候,字符串没有变,所以还是要用SIGNAL(test(Base*))
。
【讨论】:
我应该将信号设为虚拟吗?还是从基类 -> 派生类进行转换而不是使用发送者并将 QOBject 转换为基类/派生类更好? 技术上是的,尽管 moc 会给你一个警告。而且 C++ 不支持协变或逆变参数,因此test(Base*)
和 test(Derived*)
将不相关。您仍然可以通过虚拟函数或使用访问者模式执行依赖于对象本身的 Base*
或 Derived*
的部分来避免强制转换。
嗯。所以如果我理解正确,如果我在基类中的函数是虚拟的,那么如果我得到一个指向 Base* 的指针也没关系,我仍然会得到虚拟函数等。【参考方案2】:
您不应将发送者作为信号的参数。您可以简单地使用QObject::sender()
来获取发送信号的QObject
。
例如:
emit test();
然后在一个槽中:
void Listener::someObject_test()
QObject* sender = QObject::sender();
// or:
Derived* sender = (Derived*)QObject::sender();
【讨论】:
我认为文档是针对 sender() 的? 我用了好几次都没有遇到任何问题。该文档指出“此功能违反了面向对象的模块化原则”。如果将对象作为信号的参数提供,也会违反相同的原则。有时需要知道信号的来源,在这些情况下,使用QObject::sender()
是最简单的方法。
sender()
不是免费的,它锁定一个互斥体并进行列表查找。如果您将对象作为信号的参数传递,它在语义上表明该对象是消息的一部分,您不必使用强制转换来使用您的对象,并且当信号和插槽属于时它也可以工作与sender()
不同的线程。作为奖励,您甚至可以使用不是发送者的对象作为参数发出信号。
@alexidm,谢天谢地,Qt 并没有围绕每个信号将发送者作为参数发送的概念设计。否则,每次我重写 Qt 类时,我都必须重写(并复制)每个调度信号的方法。此外,您总是必须转换从QObject::sender()
获得的对象,因为它总是会给您一个QObject
(除非您需要一个QObject,这种情况很少见)。
最后,我认为列表查找不会那么慢。对于用户生成的事件,您最需要信号,这些事件并不频繁。对于更频繁的事情,可能会有一些优化。也许将发送者作为参数发送是一种优化,也许有更好的方法……但无论如何,这都是一种边缘情况,这取决于应用程序。【参考方案3】:
由于派生类没有自己的信号,你将监听测试(Base*)。
【讨论】:
以上是关于是否可以使用“this”从派生对象的基类发出信号的主要内容,如果未能解决你的问题,请参考以下文章
shared_from_this()如何在派生类中工作,该派生类继承自从enabled_shared_from_this继承的基类