【总结】connect的研究

来源:互联网 发布:ssm框架项目源码 编辑:程序博客网 时间:2024/06/03 17:11


1.函数指针

#include <iostream>
using namespace std;
void hello(){
    cout<<"abc"<<endl;
}
int abc(int x){
    return x+1;
}
typedef void (*pHello)();.........这一行就是typedef的函数指针funcpointer,其实他们就是替代关系,看懂了就
int main(int argc, char *argv[])  好说了,没看懂就觉得很深奥,*pHello就是代替了hello,那么这个指针就应该
{                                 指向hello,*phello=&hello;
    //int (*fAbc)(int axc);
    //fAbc=&abc;
    //cout<<(*fAbc)(1)<<endl;
    void (*pf)();
    pf = &hello;
    //pf = hello;
    (*pf)();
    //pf();
    pHello p = &hello;
    (*p)();
    return 0;
}
/*
typedef int (*pF)(int);     ............这个也是函数指针,这个int必须写上去标明我这里有一个参数。
pF y;                                 其余和上面差不多。
y=&abc;
cout<<(*y)(1)<<endl;
*/
2.成员变量指针
#include <iostream>
using namespace std;
class A{
  public:
    int x;
};
void func(A obj, int A::* p){//MemberPointer p
    cout<<obj.*p<<endl;
}
void func2(A * obj, int A::* p){
    cout<<obj->*p<<endl;
}
template   <class   T>    ...........c++函数模版,根据T类型来决定函数的类型避免重复编程
void func3(T * obj, int T::* p){
    cout<<obj->*p<<endl;
}
typedef int A::* MemberPointer;.........成员变量指针  替代关系
int main(int argc, char *argv[])
{
    MemberPointer pV;
    //成员变量指针的定义
    //等价于int A::* pV;
    pV = &A::x ;
    A a;
    a .* pV=1;//等价于a.x=1;
    cout << a .* pV << endl;
    func(a,pV);
    func2(&a,pV);
    func3(&a,pV);
    return 0;
}
3.比较难以理解的部分,成员函数指针
#include <iostream>
using namespace std;
class Person {
    public:
        void sayHello(){
            cout<<"hello"<<"  ";
            printf("%d\n",&Person::sayHello);
        }
        virtual void sayName(){
            cout<<"I have no name"<<"  ";
            printf("%d\n",&Person::sayName);
        }
};
class Child : public Person {
    public:
    void sayHello(){
        cout<<"Hello"<<"  ";
        printf("%d\n",&Child::sayHello);
    }
    virtual void sayName(){
        cout<<"I am XIAOMING"<<"  ";
        printf("%d\n",&Child::sayName);
    }
};
//typedef void (*FunctionPointer)();
typedef void (Person::*PersonMemberFunctionPointer)();....相比于函数指针,就多了一个部分.
typedef void (Child::*ChildMemberFunctionPointer)();      class_name::这个是域名。
void runfuncName(Person * obj, void (Person::*func)() ){//PersonMemberFunctionPointer func
    (obj ->* func)();
}
int main(int argc, char *argv[])
{
    Person someone;
    Child xiaoming;
    PersonMemberFunctionPointer pp;
    pp = &Person::sayHello;
    (someone .* pp)();
    //等价于 (&someone ->* pp)();
    //也等价于 someone.sayHello();
    (xiaoming.*pp)();
    //pp=&Child::sayHello;(不能运行,需要强制转换)
    ChildMemberFunctionPointer cp = &Child::sayHello;
    (xiaoming.*cp)();
    runfuncName(&xiaoming,pp);
    PersonMemberFunctionPointer pp2 = &Person::sayName;
    (someone.*pp2)();
    (xiaoming.*pp2)();//必须是公开继承,才有权限
    //pp2 = &Child::sayName;(不能运行,需要强制转换)
    return 0;
}
总而言之,typedef就是一个替换的过程,只要知道了替换的规则,再看懂应该就不难了。
那么接下来就看我们的connect代码。
#include <iostream>
using namespace std;
//第四步才看
class A;
class B;
typedef void (A::*Apointer)();.....成员函数指针typedef
typedef void (B::*Bpointer)();
//typedef Apointer A::* Signal;
//第一步开始看
class A {
  public:
    void (A::*click)();
    void onClicked(){
            cout<<"use my onclicked "<<endl;
        }
    //第四步才看
    B* slotObj;
    void TreatClickEvent(){
        (slotObj->*(Bpointer)click)();
    }
};
//第三步才看
class B {
  public:
    int x=5;
    void onClicked(){
        cout<<" use B onclicked the value of 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;   ...Apointer就是typedef转换,这里使用了二个typedef
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;
}
这段代码实现了A,B之间的连接,使用自己的connect函数,而不是QObject的函数;
这段代码注释很清晰了,只需要看懂前面三个,这个代码应该不太难,我就指出几个部分需要看一下的
class A {
  public:
    void (A::*click)();
    void onClicked(){
            cout<<"use my A onclicked "<<endl;
        }
    //第四步才看
    B* slotObj;
    void TreatClickEvent(){
        (slotObj->*(Bpointer)click)();
    }
};
我们看class A的定义,里面有void (A::click)这个就是singal的所在,在这里我觉得就是桥梁的
作用。slotobj是为了让信号准确找到相应的槽。
void runfuncPointer(A * obj, void (A::*( A::*pfunc ))()){ //Apointer A::* pfunc
    (obj->*(obj->*pfunc))();
}
 runfuncPointer(&a,&A::click);  出现了,这个函数,就是这个用法,然后前面的connect语句
connect(&a,&A::click,&A::onClicked);//a.click = &A::onClicked;
然后就直接执行了本A的onclicked。
这个地方是二个运用的结合,所以如果用双重typedef会简便看法。
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;
}
三个connect的代码在这里,signal为信号,slot为槽。我们这里是模拟的
void (A::*( A::*pfunc ))()
void (A::*click)();  也是一个替代。
所以signal一般都是click。
那其实connect就是制造一个槽和一个信号,然后将他们连接起来这样的功能
那么Qt里面的QObject的connect的运作方式呢

bRet = connect(m_ViewScene,SIGNAL(itemMoved(CustomItem*,const QPointF&)),this,SLOT(ItemMoved(CustomItem*,const QPointF&)));

SIGNAL()宏和SLOT()宏中的函数的参数一定要严格一致。

SIGNAL( itemMoved(CustomItem*,const QPointF&) ),SIGNAL()中是Custom*,那么SLOT()中就得是CustomItem*,否则connect()返回false,表明信号和槽没有连接成功。

void itemMoved(CustomItem *movedItem, const QPointF &movedFromPosition);

const  在connect()方法中不用出现,可以去掉。

&不可以在connect()方法中去掉,如果信号有&,那么connect()方法中必须出现&才行,否则connect()返回false。

那么我们可以看出,内部细节可能很复杂,但是基本也是这个方式,那么connect的学习还需要自己大量的使用才可以

原创粉丝点击