Windows编程之connect函数研究
写在前面:本博客为本人原创,严禁任何形式的转载!本博客只允许放在博客园(.cnblogs.com),如果您在其他网站看到这篇博文,请通过下面这个唯一的合法链接转到原文!
本博客全网唯一合法URL:http://www.cnblogs.com/acm-icpcer/p/6821921.html
Windows编程之connect函数研究
#include <iostream>
using namespace std; //第四步才看
class A;
class B;
typedef void (A::*Apointer)();
typedef void (B::*Bpointer)(); //第一步开始看
class A {
public:
void (A::*click)();//function pointer for class
void onClicked(){
cout<<"A button,A onClick function"<<endl;
} //第四步才看
B* slotObj;
void TreatClickEvent(){
(slotObj->*(Bpointer)click)();
}
}; //第三步才看
class B {
private:
int x=;
public:
//int x=5;
void onClicked(){
cout<<"A button,B onClick function,x is:"<<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;
//refers to : connect(A* a, Signal signal, Apointer slot)
(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 ;
}
直接看主函数。
主函数的代码简要看分成三个部分:
(1)
第一个部分最开始就创建了A类对象a。
首先做好必要的准备工作,即调用runfuncName函数,通过函数形参我们可以看出这个函数主要是通过传入对象指针及函数指针来调用对象的成员函数(在此处实现了调用a的onClicked函数打印提示信息)。
然后通过connect函数连接a对象中的函数指针click和函数onClicked,那么通过看函数形参我们可以知道这个connect函数的功能就是就是将信号(即函数指针click)和槽(即a对象中的函数onClicked)连接在一起,这样之后,调用click指针寻址后就可以调用a对象中的函数onClicked;效果就像是通过click这个信号触发了onClicked函数。而紧随其后的代码(a.*a.click)();就是起到了检查信号和槽是否连接成功的作用。
那么后面的函数runfuncPointer(&a,&A::click);又有什么作用呢?
把目光转向函数形参:void runfuncPointer(A * obj, void (A::*( A::*pfunc ))())
形参中的A * obj自然指要传一个A类对象的指针进来;而void (A::*( A::*pfunc ))()则表示一个指向函数指针的指针。
而函数体内的语句(obj->*(obj->*pfunc))();则是通过通过这个指向函数指针的指针来找到这个函数指针(即对象a中的信号click),从而通过这个信号触发其对应的槽(即a对象中的函数onClicked)。而为了成功执行这条语句,之前就必须通过函数connect将信号与槽连接起来,否则编译器执行到此处时报错。
那么讲到这里我们就一目了然了:函数runfuncPointer(&a,&A::click);本质上也是用来检查信号和槽是否连接成功的。实际上,这条语句被执行后和代码(a.*a.click)();一样都调用了a对象的函数onClicked,打印出提示信息A button,A onClick function。
(2)
第二个部分与第一个部分的实现目的基本一致,区别在于第二个部分希望通过A类对象的信号去驱动B类信号的成员函数。
故而主要看代码connect(&a, &A::click, &B::onClicked);
这个connect函数的形参为connect(A* a, Signal signal, Bpointer slot),它与第一部分的connect函数的不同之处在于函数体内将A类对象的信号与B类信号的槽连接:a->*signal = (Apointer) slot;,但是明显,A类信号不能直接与B类槽连接,所以在B类槽前面需要写明A类的槽的类型,以此进行强制类型转换。后面的触发信号语句也说明了这一点:
(b.*(Bpointer)a.click)();
其中,加粗语句将A类信号转换为B类信号。这条语句等价于:(fb->*(Bpointer)a.click)();(fb是B类对象的指针)。
(3)
第二部分没能实现访问B类的数据成员,比如语句(a.*a.click)();输出的x的值为随机值。
那么,为了真正的将不同类之间的信号和槽连接在一起,需要重写connect函数:
void connect(A* a, Signal signal, B* b, Bpointer slot){
a->*signal = (Apointer) slot;
a->slotObj = b;
}
connect(&a, &A::click, fb, &B::onClicked);
可以看出,这个connect函数与第二部分的connect函数的最大不同只在于多写了一句a->slotObj = b;,那么这句话将A类对象内部的B类对象指针指向指定的B类对象,以便在A类对象内部通过函数TreatClickEvent触发信号,以真正的连接不同类之间的信号与槽。
这之后,用语句a.TreatClickEvent();在对象中触发信号,便可以真正的访问B类对象的数据成员了。
by TZ@华中农业大学
2017/5/7
Windows编程之connect函数研究的更多相关文章
- linux网络编程之IO函数
Linux操作系统中的IO函数主要有read(),write(),recv(),send(),recvmsg(),sendmsg(),readv(),writev(). 接收数据的recv()函数 # ...
- C Socket编程之Connect超时 (转)
网络编程中socket的分量我想大家都很清楚了,socket也就是套接口,在套接口编程中,提到超时的概念,我们一下子就能想到3个:发送超时,接收超时,以及select超时(注:select函数并不是只 ...
- windows编程之Windows Shell 编程
参考书<VC++ Windows Shell Programming> 这里仅仅是记录下该资源,推荐到下文列出的连接进行查看 用VC++ 进行Windows Shell 扩展编成 ...
- Linux下多进程编程之exec函数语法及使用实例
exec函数族 1)exec函数族说明 fork()函数用于创建一个子进程,该子进程几乎复制了父进程的全部内容,但是,这个新创建的进程如何执行呢?exec函数族就提供了一个在进程中启动另一个程序执行的 ...
- (十)Linux 网络编程之ioctl函数
1.介绍 Linux网络程序与内核交互的方法是通过ioctl来实现的,ioctl与网络协议栈进行交互,可得到网络接口的信息,网卡设备的映射属性和配置网络接口.并且还能够查看,修改,删除ARP高速缓存的 ...
- C库函数标准编程之fscanf()函数解读及其实验
函数功能 fscanf()函数用于从参数stream的文件流中读取format格式的内容,然后存放到...所指定的变量中去.字符串以空格或换行符结束(实验1中会对它进一步说明) 函数格式 字符格式说明 ...
- python3 第二十一章 - 函数式编程之return函数和闭包
我们来实现一个可变参数的求和.通常情况下,求和的函数是这样定义的: def calc_sum(*args): ax = 0 for n in args: ax = ax + n return ax 但 ...
- 函数式编程之-bind函数
Bind函数 Bind函数在函数式编程中是如此重要,以至于函数式编程语言会为bind函数设计语法糖.另一个角度Bind函数非常难以理解,几乎很少有人能通过简单的描述说明白bind函数的由来及原理. 这 ...
- Linux编程之fork函数
在Linux中,fork函数的功能就是在一个进程中创建一个新的进程,当前调用fork函数的进程就是产生的新进程的父进程,新进程在以下也称为子进程.在新进程生成之后就会在系统中开始执行. 函数原型:pi ...
随机推荐
- polarssl rsa & aes 加密与解密
上周折腾加密与解密,用了openssl, crypto++, polarssl, cyassl, 说起真的让人很沮丧,只有openssl & polarssl两个库的RSA & AES ...
- Nginx(十)-- 进程模型及工作原理
1.nginx进程模型 Nginx是一个master和worker的模型.master主要用来管理worker进程,master就比作老板,worker就是打工仔,master指挥worker来做事情 ...
- 雷达波Shader
OSG版本: vert #version varying out vec3 v; void main() { gl_FrontColor = gl_Color; gl_Position = ftran ...
- Objective-c官方文档 怎么自定义类
通过类别来给已经存在的类添加方法来实现自定义类 如果你需要添加一个方法给一个已经存在的类,也许能增加新的功能使你更容易来在我们的应用里处理一些事情.最简单的方法是用类别. 这个语法有点想类的接口描述但 ...
- 【EF框架】另一个 SqlParameterCollection 中已包含 SqlParameter。
查询报表的时候需要通过两次查询取出数据. 第一次,用count(*)查出总数: 第二次,用rownumber分页取出想要的页内容: 为了防止sql注入,使用SqlParameter来传递参数 var ...
- 【十大算法实现之naive bayes】朴素贝叶斯算法之文本分类算法的理解与实现
关于bayes的基础知识,请参考: 基于朴素贝叶斯分类器的文本聚类算法 (上) http://www.cnblogs.com/phinecos/archive/2008/10/21/1315948.h ...
- html2canvas - 实现网页截图(+下载截图) 功能
实现:html2canvas + canvas.toDataURL 首先,引入依赖插件: import { html2canvas } from './html2canvas'; html2canva ...
- 反编译获取线上任何微信小程序源码(转)
看到人家上线的小程序的效果,纯靠推测,部分效果在绞尽脑汁后能做出大致的实现,但是有些细节,费劲全力都没能做出来.很想一窥源码?查看究竟?看看大厂的前端大神们是如何规避了小程序的各种奇葩的坑?那么赶紧来 ...
- linux编码问题小节
今天又碰到了难缠的python编码问题,首先主要还是linux操作系统中的编码问题. 无论怎么样,我都没办法在linux的vim中利用中文输入法打出中文? vim中的set encoding,set ...
- 23种设计模式之桥接模式(Bridge)
桥接模式将抽象部分与它的实现部分分离,使它们都可以独立地变化.它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式.桥接模式类似于多重继承方案,但是 ...