实验框架说明
编译运行环境
Ubuntu Kylin 20.04.3 LTS + Qt 5.12.8 + GCC
Child类
首先声明一个子类Child,为了之后能够支持Qt信号量,让他继承QObject,因为我有多线程需要,QThread继承QObject,因此这里直接继承QThread。
class Child:public QThread
{
Q_OBJECT
public:
explicit Child(){
// connect(this, &Child::SN_Req, this, [this](void in()){in();});
connect(this, &Child::SN_Req2, this, [this](std::function<int()> in){in();});
connect(this, &Child::SN_Req3, this, [this](std::function<void()> in){in();});
// SN_Req([](){qDebug() << "SN_Req CallBack1";});
// SN_Req([this](){qDebug() << "SN_Req CallBack2";});
}
~Child(){;}
void func1();
void func3(void in()){in();};
void func4(std::function<void()> in){if (in) in();};
signals:
// void SN_Req(void in());
void SN_Req2(std::function<int()> in);
void SN_Req3(std::function<void()> in);
};
Parent类
再声明一个parent类,有一个Child类成员。
class Parent : public QObject
{
Q_OBJECT
public:
explicit Parent(QObject *parent = nullptr);
// void func5(void Child::func2()){in();};
int val;
private:
Child a;
};
函数回调
我们看Child里面的func3、func4,这两种都是用于函数回调的例子。
所谓回调函数,其实就是把函数作为指针参数传进调用的函数里,然后在调用的函数里,在调用这个指针函数。看着非常复杂对吧,其实完全不用去考虑什么指针函数、函数指针,直接把函数整个放进去就行。
void func3(void in()){in();};
或者使用C++11标准里的function:
void func4(std::function<void()> in){if (in) in();};
这两者在函数回调里面用法大概是没什么区别的,但到了下面信号回调就不一样了。
C函数回调
我们在main函数里实例化Child,并在main函数前定义一个用于回调的C函数:
void funco1(){
qDebug() << "normal func";
}
int main(int argc, char *argv[])
{
Child a1;
Parent t;
a1.func3(
a1.func4(
a1.func3([](){qDebug() << "lambda func3";});
a1.func4([](){qDebug() << "lambda func4";});
// a1.func3(
return 0;
}
可以看到,无论是普通的C函数还是不带this的lambda函数都一视同仁,func3、func4都很好地支持了。
类成员函数回调
但是如果你想把a1的func1传进去却不行,因为C++类成员函数跟C函数是不一样的,具体是关于地址动态和固定的问题,有兴趣可以单独去了解。
// a1.func3(
但是你可以在Parent的函数里面把带this的lambda传进去,比如在构造函数里:
// a.func3([this](){qDebug() << b.val;});
a.func4([this](){qDebug() << b.val;});
看到没,这里就有区别了,fun3是不能传带this的,但func4可以。
信号回调
现在如果我想发射一个信号,让接收到这个信号的类在执行完之后,调用这个回调函数,要怎么做?
这里就只能采取类似func4的方法:
signals:
// void SN_Req(void in());
void SN_Req3(std::function<void()> in);
SN_Req虽然在编写代码的时候不会警告,但编译是无法通过的。
然后需要在槽里面回调这个函数:
connect(this, &Child::SN_Req3, this, [this](std::function<void()> in){in();});
在Parent类里面调用这个信号也是没有限制的,可以将this捕获:
a.SN_Req3([this](){qDebug() << val;});
但要注意,如果两个类运行的线程不一样的话,信号槽不是直连,就需要注册这个类型:
qRegisterMetaType< std::function<void()> >("std::function<void()>");