深⼊理解Qt中connect函数#include <iostream>
using namespace std;
//第四步才看
class A;
class B;
typedef void (A::*Apointer)();
typedef void (B::*Bpointer)();
//第⼀步开始看
class A {
public:
void (A::*click)();
void onClicked(){
cout<<"按A上⾯的按钮,调⽤了⾃⼰的onClick函数!"<<endl;
}
//第四步才看
B* slotObj;
void TreatClickEvent(){
(slotObj->*(Bpointer)click)();
}
};
//第三步才看
class B {
指针调用成员函数
public:
int x=5;
void onClicked(){
cout<<"按A上⾯的按钮,调⽤了B的onClick函数! 成员变量x的值为"<<x<<endl;
}
};
//第⼀步开始看:复习成员变量指针
void runMemberVariblePointer(A * obj, int A::* pMember) {
cout<<obj->*pMember<<endl;
}
//第⼀步开始看:复习成员函数指针
void runfuncName(A * obj, void (A::*func)()){
(obj->*func)();
}
//第⼀步看:组合成员变量指针和成员函数指针
void runfuncPointer(A * obj, void (A::*( A::*pfunc ))()){ //Apointer A::* pfunc
(obj->*(obj->*pfunc))();
}
//typedef void (A::*Apointer)();
//第⼆步才看
//typedef void (A::*(A::*Signal))();
typedef Apointer A::* Signal;
void connect(A* a, Signal signal, Apointer slot){ //void (A::*slot)()
a->*signal = slot;
}
//第三步才看
void connect(A* a, Signal signal, Bpointer slot){
a->*signal = (Apointer) slot;
}
//第四步才看
void connect(A* a, Signal signal, B* b, Bpointer slot){
a->*signal = (Apointer) slot;
a->slotObj = b;
}
int main(int argc, char *argv[])
{
//第⼀步、理解信号的本质:成员函数指针类型的特殊成员变量
//第⼆步、连接A本⾝的信号与槽
A a;
runfuncName(&a,&A::onClicked);
connect(&a,&A::click,&A::onClicked);//a.click = &A::onClicked;
(a.*a.click)();
runfuncPointer(&a,&A::click);
//第三步:连接A的信号到B的槽
B b; B * fb = &b;
connect(&a, &A::click, &B::onClicked);//a.click = (void (A::*)())&B::onClicked;
(a.*a.click)();
(b.*(Bpointer)a.click)();//(fb->*(Bpointer)a.click)();
//第四步:完善连接A的信号到B的槽
connect(&a, &A::click,
fb, &B::onClicked);
a.TreatClickEvent();
return0;
}
第⼀步:
  ⾸先通过runMemberVariblePointer(A * obj, int A::* pMember)、runfuncName(A * obj, void (A::*func)())复习了之前成员变量指针和成员函数指针的⽤法。
  然后再来看runfuncPointer(A * obj, void (A::*( A::*pfunc ))()),这⾥参数void (A::*( A::*pfunc ))()是指向成员函数指针的指针,在主函数中通过runfuncPointer(&a,&A::click);调⽤它,其中&A::click是在A类中声明的成员函数指针的地址,但这⾥(A::*click)()没有指向任何⼀个函数,所以继续往下看。
第⼆步:
  ⾸先通过typedef Apointer A::* Signal;定义了指向成员函数指针的指针,这么做的⽬的是为了之后更加简洁的定义指向成员函数指针的指针。
  然后来看connect(A* a, Signal signal, Apointer slot) 函数,signal就是指向成员函数指针的指针,slot为成员函数指针,这是再回头看之前的问题,主函数在调⽤runfuncPointer(&a,&A::click);之前,调⽤了connect(&a,&A::click,&A::onClicked);,其中&A::click是在A类中声明的成员函数指针的地址,&A::onClicked是成员函数onClicked()的地址,通过connect()函数可以将函数地址slot传递给函数指针a->*signal,相当于连接signal和slot,这时调⽤runfuncPointer(&a,&A::click);就可以得到结果"按A上⾯的按钮,调⽤了⾃⼰的onClick函数!"。
第三步:
⾸先看 connect(A* a, Signal signal, Bpointer slot),与第⼆步相同,只不过slot是Bpointer类型,并且函数体中a->*signal = (Apointer) slot;⽤了强转。
在主函数中调⽤connect(&a, &A::click, &B::onClicked);,这⾥传⼊了B类成员函数的地址,然后对象a调⽤成员函数指针(a.*a.click)();,结果为"按A上⾯的按钮,调⽤了B的onClick函数! 成员变量x的值为4358424",这⾥x为随机数,因为这⾥通过强转访问的B的onClick函数,但它并没有访问b对象的内存。
之后主函数中(b.*(Bpointer)a.click)();,将A类的成员函数指针强转为B类型的,并⽤对象b调⽤,结果为"按A上⾯的按钮,调⽤了B的onClick函数! 成员变量x的值为5",这⾥⽤对象b调⽤,所以x=5。
第四步:
⾸先看connect(A* a, Signal signal, B* b, Bpointer slot),它的函数体将b的地址给了A类中B类型的对象指针slotObj,其他的与第⼆步分析相同。
主函数中connect(&a, &A::click,fb, &B::onClicked);连接signal和slot,最后调⽤a.TreatClickEvent();,直接访问B的onClick函数,所以结果为"按A上⾯的按钮,调⽤了B的onClick函数! 成员变量x的值为5"。