Qt 子类重新实现父类的槽函数

在重写槽函数时发现没有被调用(后来发现重写错了类,应该是重写类a,结果写的类b,测试时,只测试到了a),于是写了测试代码验证。

#ifndef PARENTSLOT_H
#define PARENTSLOT_H

#include <QObject>
#include <QDebug>
#include <QThread>
class parentSlot:public QObject
{
    Q_OBJECT
public:
    parentSlot(QObject*p = nullptr)
    {
//        connect(this,&parentSlot::signalTest,this,&parentSlot::slotTest,Qt::QueuedConnection);
//        connect(this,&parentSlot::signalTest,this,&parentSlot::slotTest,Qt::BlockingQueuedConnection);

        connect(this,SIGNAL(signalTest()),this,SLOT(slotTest()));
//        connect(this,SIGNAL(signalTest()),this,SLOT(slotTest()),Qt::QueuedConnection);

        emit signalTest();
//        slotTest();
    }
signals:
    void signalTest();
    void signal2();
public slots:
    virtual void slotTest()
    {
        QThread::sleep(3);
        qDebug() << " this is parent slotTest ";
//        emit signal2();
    }
};
class childSlot:public parentSlot
{
    Q_OBJECT
public:
    childSlot(QObject*p = nullptr):parentSlot(p)
    {
        connect(this,&childSlot::signal2,this,&childSlot::slotChildTest);
//        emit signalTest();

    }
public slots:
    void slotTest(){
        qDebug() << " this is child slotTest start";

        parentSlot::slotTest();
        qDebug() << " this is child slotTest end";
        emit signal2();
    }

    void slotChildTest(){qDebug() << " this is child slotChildTest ";}
};
#endif // PARENTSLOT_H

这里在父类中关联了信号槽,也触发了信号,结果就是只调用到了父类的槽函数实现。因为信号接受和发送者是在同一个线程中,关联信号默认是Qt::AutoConnection,立即调用槽函数。

如果改成connect(this,SIGNAL(signalTest()),this,SLOT(slotTest()),Qt::QueuedConnection);这样就可以调用子类实现,如果信号关联和触发都在基类中,则只有用Qt::QueuedConnection才能调用子类实现

如果信号signalTest是在子类构造中触发,则可以直接调用子类实现

如果信号在其他地方emit触发,也是可以直接调用子类实现

    parentSlot(QObject*p = nullptr)
    {        connect(this,&parentSlot::signalTest,this,&parentSlot::slotTest,Qt::BlockingQueuedConnection);
        qDebug() << QThread::currentThreadId() << " parentSlot," << QThread::currentThread();        emit signalTest();

    }

在main.cpp里

    QThread thread;
    qDebug() << "thread " << thread.thread();
    qDebug() << "currentThread " << QThread::currentThread()->currentThreadId();

    childSlot t;
    t.moveToThread(&thread);
    thread.start();

qDebug() << "end";

结果报错 死锁了

thread  QThread(0xbfff90)
currentThread  0x7fc83a6f4740
0x7fc83a6f4740  parentSlot, QThread(0xbfff90)
Qt: Dead lock detected while activating a BlockingQueuedConnection: Sender is parentSlot(0x7fffdaad3160), receiver is parentSlot(0x7fffdaad3160)

这里childSlot t;在主线程里构造,信号也是在构造函数中触发的,但实际确是认定信号是在子线程里触发,槽函数也是在子线程里,用了Qt::BlockingQueuedConnection,信号发起的线程要阻塞等槽的执行结束,就死锁了

    parentSlot(QObject*p = nullptr)
    {  

//        connect(this,SIGNAL(signalTest()),this,SLOT(slotTest()));
        connect(this,SIGNAL(signalTest()),this,SLOT(slotTest()),Qt::QueuedConnection);
        qDebug() << QThread::currentThreadId() << " parentSlot," << QThread::currentThread();
    }

main.cpp

    QThread thread;
    qDebug() << "thread " << thread.thread();
    qDebug() << "currentThread " << QThread::currentThread()->currentThreadId();

    childSlot t;
    t.moveToThread(&thread);
    thread.start();
    QMetaObject::invokeMethod(&t, "slotTest", Qt::BlockingQueuedConnection); // 主线程调用了子线程里的槽函数,且阻塞等待槽函数执行结束才执行下面语句
    qDebug() << "end";

结果是

thread  QThread(0x1078f90)
currentThread  0x7f2a9f1cd740
0x7f2a9f1cd740  parentSlot, QThread(0x1078f90)
 this is child slotTest start
0x7f2a9a5c2700 , QThread(0x7ffc4d70c9c0)
 this is parent slotTest 
 this is child slotTest end
 this is child slotChildTest 
end

如果QMetaObject::invokeMethod(&t, "slotTest", Qt::QueuedConnection);

则结果就是主线程调用了子线程里的槽函数,且继续执行下面语句,槽函数则在子线程里待事件循环空闲得以调用

thread  QThread(0x2603f90)
currentThread  0x7f43b5aac740
0x7f43b5aac740  parentSlot, QThread(0x2603f90)
end
 this is child slotTest start
0x7f43b0ea1700 , QThread(0x7ffcbc114600)
 this is parent slotTest 
 this is child slotTest end
 this is child slotChildTest 

Qt::AutoConnection 信号发起者和信号接受者在同一个线程就是Qt::DirectConnection立即调用,不在一个线程就是Qt::QueuedConnection,待接受者的线程事件循环空闲调用

Qt::DirectConnection 信号的发起者线程里立即调用

Qt::QueuedConnection 待接受者的线程事件循环空闲调用

Qt::BlockingQueuedConnection 信号发起的线程会阻塞等待槽函数执行完才能继续,所以得是不同的线程才行,不然就会死锁

Qt::UniqueConnection 与上面的用 | 结合使用,确保不再重复连接

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值