本座觉得Wt的信号槽系统跟QT的信号槽系统相比难用一些,因为它是直接用成员函数指针的方式来绑定信号槽的。
这次遇到的问题是,在DirChooseDialog类中重载咯两个PopNode函数:
• void PopNode(); //!<填充节点。
• void PopNode( bool IsSltd); //!<填充节点。
本座需要把一个WTreeNode的selected信号连接到 void DirChooseDialog ::PopNode( bool IsSltd)。由于一开始不了解Wt中信号槽的具体实现方式,并且WTreeNode的selected信号本身带有一个bool类型的参数,所以本座以为会实现自动匹配,于是照常这样写:
CrtTrNd->selected().connect( this ,&DirChooseDialog::PopNode); //被选中,则填充。
这里的CrtTrNd是一个WTreeNode的指针。
结果在编译过程中,g++报告错误:
error: call of overloaded 'connect(DirChooseDialog* const, <unresolved overloaded function type>)' is ambiguous
/usr/include/Wt/WSignal:915: note: candidates are: boost::signals::connection Wt::Signal<A1, A2, A3, A4, A5, A6>::connect(T*, void (V::*)()) [with T = DirChooseDialog, V = DirChooseDialog, A1 = bool, A2 = Wt::NoClass, A3 = Wt::NoClass, A4 = Wt::NoClass, A5 = Wt::NoClass, A6 = Wt::NoClass]
/usr/include/Wt/WSignal:905: note: boost::signals::connection Wt::Signal<A1, A2, A3, A4, A5, A6>::connect(T*, void (V::*)(A1)) [with T = DirChooseDialog, V = DirChooseDialog, A1 = bool, A2 = Wt::NoClass, A3 = Wt::NoClass, A4 = Wt::NoClass, A5 = Wt::NoClass, A6 = Wt::NoClass]
make: *** [DirChooseDialog.o] Error 1
本座表示完全看不懂,对于函数模板完全是菜鸟。于是去Wt论坛问老外,经过老外的指点,并且搜索参考咯一些资料之后,终于解决问题咯。
这里是老外的指点:http://redmine.emweb.be/boards/2/topics/4279,告诉本座说研究方向应该是指向重载的成员函数的函数指针。
在Wt中,绑定的信号槽是以成员函数指针的方式传递给Wt::Signal::connect函数的,这个connect函数本身是重载的,会根据传递给它的参数的不同而调用不同的connect函数,其中的一个参数便是要连接到的目标信号槽函数的成员函数指针。这是本座自己的理解。
然后就是这位哥哥的勃客咯: http://www.cppblog.com/woaidongmao/archive/2011/06/21/149128.html ,这句话写得狠准确: 现在要考虑用指针来指向重载函数了,你就得把重载函数的每一个成员视为相互独立的函数。虽然给指针赋值的语句是那么相似,但是实际上被赋值的指针获得的是某个特定的函数,而其它“同名”的函数就像不存在一样。 也就是说,无论你把一个函数重载咯多少次,一旦有一个函数指针确定咯自己要指向的目标函数的类型(由参数列表、返回值来唯一确定),则该函数的其它重载函数在这个指针眼里就是浮云咯,只需将函数名(无需带返回值,无需带参数表)作为右值传递给该函数指针即可。这里的关键在于,对于函数的重载和函数指针来说,判定其唯一性的标准不相同,就像哥哥所说,对于函数指针来说,重载函数的每一个成员都视为一个独立的函数。这样,当妳要让某个函数指针指向重载函数中的一个特定成员时,妳需要在一开始声明此函数指针时便将该函数指针的类型写成与该特定成员相同的类型。这个例子狠传神:
void GetVal(int);//重载函数一
void GetVal(double *);//重载函数二
void GetVal(string &);//重载函数三
void (*pFun1)(int);//指针一
void (*pFun2)(double *);//指针二
void (*pFun3)(string &);//指针三
void (*pFun4)(double);//指针四
pFun1 = GetVal;//获取函数一的地址
pFun2 = GetVal;//获取函数二的地址
pFun3 = GetVal;//获取函数三的地址
pFun4 = GetVal;//错误,没有对应的函数可以获取
所以在本座自己的这个案例中,需要先声明一个与void DirChooseDialog ::PopNode( bool IsSltd)类型相同的函数指针,再将该成员函数的地址赋值给该指针。就要声明这样一个指针:
void ( DirChooseDialog ::*Func2Bind)( bool ); //要绑定的成员函数指针。
最后就是这位哥哥的勃客: http://www.yitsoft.com/chap_study/ch_00020/ch_00020.asp ,写明咯指向成员函数的指针该怎么声明,以及怎么赋值。就像上面写的,Func2Bind此时就是一个指针本身的变量名咯,看起来跟平常的变量声明有点不同,它被一个函数的“原型”包在其中。
将这些信息总结在一起,就能解决本座的问题,这样写代码:
void ( DirChooseDialog ::*Func2Bind)( bool ); //要绑定的成员函数指针。
Func2Bind=& DirChooseDialog ::PopNode; //为指针赋值。
CrtTrNd->selected().connect( this ,Func2Bind); //被选中,则填充。
在这里,给Func2Bind赋值时,只需将& DirChooseDialog ::PopNode赋值给它即可,因为前面的声明中已经确定咯,它要指向的是重载函数中的一个特定成员,其它成员对此指针来说是不存在的。
经过检验,连接到的确实是本座想要连接的那个特定成员函数。
感谢所有走在前面的探索者。
HxLauncher: Launch Android applications by voice commands