在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 踩