深入理解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();

    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"。


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM