#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(); return 0; }
第一步:
首先通过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"。