在windows的课堂上,一直在讲解关于connect的有关方面,那么接下来就给出我的一些分析。
首先我们是自行研究的connect 那就得写出自己的connect函数,那么接下来就是得了解一些基础知识。
为了让有些表达看起来很简便,我们需要使用自定义类型。typedef
部分QT代码不能识别汉语。所以把部分代码编程了英文以便于调试输出查看结果。
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)();.....成员函数指针typedeftypedef 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转换,这里使用了二个typedefvoid 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的学习还需要自己大量的使用才可以
顶
- 0
踩