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