是否可以使用“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 中看到该列表)。 SIGNALSLOT 宏也返回字符串,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继承的基类

在基类类型的向量中保存的基对象和派生对象被切片

使用具有指向派生类对象的指针的基类指针数组调用派生类方法

朋友类对象可以在其成员函数中访问派生类对象上的基类私有成员吗?

Java基础—面向对象的三大特性