C++ 回调url怎么实现如何实现异

C++中实现类回调的办法
我的图书馆
C++中实现类回调的办法
当我们使用普通函数做为回调函数时, 一般格式如下:&typedef int (*pFunc) (int , int) ;&但是如果要使用类成员函数做为回调函数时, 我们想到的格式会是下面的样子:&typedef int (*CClassName::Func) (int, int) ;&如是经过类型检查时, 会如愿收到如下的错误:&error C2350: 'CClassName::Func' is not a static member&这是因为普通成员函数和静态成员函数在内存中的位置是不一样的. 普通成员函数在代码区该类的代码区间中 , 而静态成员函数则和普通函数一样存储在数据区, 只是比普通函数多了一个作用域区分符而已. 问题就是: 有办法使用普通成员函数做为回调函数使用吗?&解决办法:&答案是肯定的. 但是要做到这点必须先解决两个问题: 一是如何获取函数的地址并传递到无类型指针中去,或者其他类型指针. 主要是要去掉作用域区分符.二是获取了函数地址之后如何调用函数.&第一个问题的解决中间运用了编译器的一个技巧. 我们知道所有的转换或者匹配必须经过类型检查, 除了使用可变参数的函数之外. 这样我们就可以把 CClassName::Func 以可变参数的形式转换成指针, 从而获取除去类对象地址之后的函数偏移地址.&第二个问题问题就是如何调用函数的问题. 我们知道所有类对象都隐藏了一个指象对象自己的this指针. 只要我们把类对象的地址传递过来, 我们就有了对象的基址, 加上上面获得的偏移就可以完全访问类成员函数了. 我们知道一般函数的调用约定都属于 __stacall, 这种调用约定是先将调用者入栈,然后是地址, 然后是参数从右至左依次入栈. 这样我们使用一段汇编代码就可以手动完成函数的调用了. 将类对象指针存入ECX寄存器, 然后依次压入参数.&关键代码:&第一个问题的解决代码如下:&void* OffsetToVoid( void* Dummy, ... )&{&va_&void* RetV&va_start( list, Dummy );&RetVal = va_arg( list, void* );&va_end( list );&return RetV&}&将函数偏移地址以可变参数的形式传递进来, 避过类型检查.&第二个问题的解决代码:&int Call( void* pObj,&void* pOffset,&int arg1,&int arg2 )&{&__asm&{&mov ecx,[pObj];&push arg2;&push arrg1;&call [pOffset];&}&}&将参数压栈, 并调用函数 .&使用方法:&CClassN&int nR&nRet = Call( &obj,&OffsetToVoid(0, CClassName::Func)&value1,&value2);&PS: 类成员函数也必须满足__stdcall(Pascall)式调用约定.&&附件中为源代码。
[转]&[转]&[转]&[转]&[转]&[转]&
喜欢该文的人也喜欢什么是回调?通常发生在需要两个角色即调用者与实现者的情形上,即我们希望当产生某个事件时,调用实现者定义的某个函数。当然这个概念很大,不是说操作系统的信号量,条件变量什么的,是在语言级别实现,如一个Framework提供商,规定了整个程序的框架,可能产生某事件时它希望调用某个行为,而这个行为的具体定义是由framework客户来完成。
我们从简单的做起,通过一个个为什么最终来获得一个比较好的回调实现。
C语言中用全局函数实现回调最简单了:
void callback(int a)
cout&&"callback called with para="&&a&&
typedef void (*pfunc)(int);void caller(pfunc p)
}int main(int argc, char* argv[])
caller(&callback);
相信不用多解释了吧, 可是到了面向对象的世界里,就不是那么简单了,如果回调函数是成员函数怎么办?
非静态成员函数作回调函数
当然如果是静态成员函数就好办跟全局函数是类似,到此为止世界还没有变乱,如在VC编程中用AfxBeginThread开启一个线程,就经常将参数AFX_THREADPROC pfnThreadProc定义为一个全局函数或静态成员函数,可是这两个都不方便访问类的非静态成员,之所以郑重其事地写这篇文章,就是以前静态回调用起来非常不爽。
回调函数是非静态成员函数呢?我们可不能简单地设为这样:
class CCallback
void Func(int a)
cout&&"member function callback called with para="&&a&&
typedef void (CCallback::*pMemberFunc)(int);void Caller(pMemberFunc p)
这样编译就不会通过的,因为非静态的成员函数必须通过对象来访问,好,我们稍稍改进一下:
class CCallback
void Func(int a)
cout&&"member function callback called with para="&&a&&
typedef void (CCallback::*pMemberFunc)(int);void Caller(CCallback* pObj,pMemberFunc p)
(pObj-&*p)(1);
}int main(int argc, char* argv[])
Caller(&obj,&CCallback::Func);
即给Caller多传个对象进去,好吧,貌似问题解决了,可是,调用者(如库的提供商)只知道回调函数接口长这样而已,事先全然不知客户的类是如何定义,终于模板登上场了:
template&typename T&void Caller(T* pObj,void (T::*p)(int))
(pObj-&*p)(1);
其他不变的,把调用者这里换成模板就OK了,当然这个Caller也可以是成员函数,现在用这个方法写个小应用是没什么问题了,但是限制多多,如调用者一次只调用了一个实现,但现实情况往往是产生某个事件时,应该依次调用多个行为,即把挂在这个事件上的所有回调函数通通临幸一遍,还有回调是如此的重要,以至于C#不用库在语言本身层面就实现了它,我们也不可以到此草草了事,而是按照组件化的思维提供一套完善的回调机制,所谓完善,如上个例子中Caller只能接收一个参数为int,返回值为void的成员函数指针,等等,必须是这样的接口吗,想想参数为double行不行,如void (T::*p)(double)这样的函数传给它可以吗,int不是可自动转换为double吗,那这个函数指针也能自动转换吗,就像C#中的协变与逆变一样,不行,C++不允许,当然我们可以强制转换,不过要在十分清楚类型的情况下才能这么做,否则因为不是类型安全的很容易引起程序错误甚至崩溃。所以要支持各种参数,多个参数,还得模板,嗯嗯,努力尚未成功,同志还需革命!
甭管什么名词,总之我们的目的是:产生某个事件时,调用某个待客户实现的行为,调用者什么时候调用确定了,关键是客户按照规定接口实现这个行为,这听起来有点像多态了,是的,有时候被调用者与调用者是继承关系,这就不需要其它理论了,就多态呗,不过多态不一定非得用虚函数来实现,就像MFC一样,考虑到每个类背负一个庞大的虚函数表会带来很大的性能损失,换做用几个结构体和强大的宏而实现消息映射。在wincore.cpp中,CWnd::OnWndMsg源码里,当来了消息,在事先建立的链表中从派生类依次向上查找第一个实现了这个消息的类的AFX_MSGMAP结构体,再取得它的AFX_MSGMAP_ENTRY成员,即真正的消息入口地址,
struct AFX_MSGMAP_ENTRY
// windows message
// control code or WM_NOTIFY code
// control ID (or 0 for windows messages)
UINT nLastID;
// used for entries specifying a range of control id's
// signature type (action) or pointer to message #
// routine to call (or special value)};
就类似于写一个普通的链表结构:struct list_node{list_node* int data},只不过这里的链表的next不能再随便指,要指向基类的节点,根据next指针找到对应的节点后取出数据data成员即可,在这里,data就是AFX_MSGMAP_ENTRY,如上图,AFX_MSGMAP_ENTRY里定义了消息标号即各种附加参数,还有最关键的成员pfn,代表了事先派生类通过宏填充好的回调成员函数地址。但是pfn的类型即AFX_PMSG定义为typedef void (AFX_MSG_CALL
CCmdTarget::*AFX_PMSG)(void); 只能代表一种类型,而客户的派生类的为响应消息的回调函数的类型有很多种,在框架中如何保证以正确的形式调用呢?原来客户在填充消息标号和函数地址时,也顺便填充好了函数类型交给nSig成员保存,根据nSig,如前文所说,将pfn强制转换到相应的类型就OK了,不过这成员函数指针转换来转换去,代码非常难看啊可读性不强,于是使用union进行类型转换:
//afximpl.hunion MessageMapFunctions
// generic member function pointer
// specific type safe variants for WM_COMMAND and WM_NOTIFY messages
void (AFX_MSG_CALL CCmdTarget::*pfn_COMMAND)();
BOOL (AFX_MSG_CALL CCmdTarget::*pfn_bCOMMAND)();
void (AFX_MSG_CALL CCmdTarget::*pfn_COMMAND_RANGE)(UINT);
BOOL (AFX_MSG_CALL CCmdTarget::*pfn_COMMAND_EX)(UINT);
}//wincore.cpp
CWnd::OnWndMsgunion MessageMapF
mmf.pfn = lpEntry-&
nSig = lpEntry-&nSswitch (nSig)
ASSERT(FALSE);
case AfxSig_bD:
lResult = (this-&*mmf.pfn_bD)(CDC::FromHandle((HDC)wParam));
case AfxSig_bb:
// AfxSig_bb, AfxSig_bw, AfxSig_bh
lResult = (this-&*mmf.pfn_bb)((BOOL)wParam);
case AfxSig_bWww:
// really AfxSig_bWiw
lResult = (this-&*mmf.pfn_bWww)(CWnd::FromHandle((HWND)wParam),
(short)LOWORD(lParam), HIWORD(lParam));
当然这里只是一个小插曲而已,它只是MFC为满足于自己应用设计这么一套机制,派生类的回调函数类型是有限的,再则要求与框架类是继承关系,如果没有继承关系怎么办,例如当产生串口或者网口收到数据的事件时,需要更新UI界面,UI界面与串口类可是没有丝毫继承关系的,呃...铁人王进喜说:有条件要上,没条件创造条件也要上,我们大不了专门定义一个回调抽象类,让UI界面继承自它,实现类里的回调函数,然后串口类通过抽象类型对象指针就可以多态地调用到UI的真正回调实现。COM/ATL的回调,Java的回调就是这么干。不过在C++中,情形有些不一样,这样实现很勉强,它需要多重继承,仍然不能直接实现同时调用多个行为,耦合性高,每个回调都需要单独定义一个类(只要接口不一样),效率也不够高,我们想直接调用到绑定好的回调,基于这些缺点,还得寻找更好的方法。
信号与槽(Signal/Slots)
说了这么多,终于来到正题了,在C++中,信号与槽才是回调的完美解决方案,其实本质上是一个观察者模式,包括其它的叫法:delegate,notifier/receiver,observer,C#中的delegate也是一个观察者的实现。Qt中提供了信号与槽的整套机制,任何对象的槽可以绑定到另一个对象的信号上,一个信号可以拥有多个槽,经典的图例如下:
可是qt中的实现用了signal slot关键字,不是C++标准的啊,其它编译器不能随便编译(好像先经过qmake生成标准的代码就可以了),直接上源码不妥得搞清楚为什么,一切从最简单的入手,我们先来用标准C++实现一个简易的signal/slots,如何实现呢,说白了,就是想方设法把回调函数信息保存起来,必要时利用它就OK了,回调函数信息就两个,类对象指针与成员函数地址,我们将这对信息存储到名叫slot的类中,而在signal类中,维护多个slot即可,仍然用带一个int参数,返回值为void的函数接口:
#include &vector&
#include &iostream&using namespace
template&typename T, typename T1&class slot
slot(T* pObj,void (T::*pMemberFunc)(T1))
m_pMemberFunc=pMemberF
void Execute(T1 para)
(m_pObj-&*m_pMemberFunc)(para);
void (T::*m_pMemberFunc)(T1);
template&typename T, typename T1&class signal
void bind(T* pObj,void (T::*pMemberFunc)(T1 para))
m_slots.push_back(new slot&T,T1&(pObj,pMemberFunc));
vector&slot&T,T1&* &::iterator ite=m_slots.begin();
for (;ite!=m_slots.end();ite++)
void operator()(T1 para)
vector&slot&T,T1&* &::iterator ite=m_slots.begin();
for (;ite!=m_slots.end();ite++)
(*ite)-&Execute(para);
vector&slot&T,T1&* & m_
};class receiver
void callback1(int a)
cout&&"receiver1: "&&a&&
void callback2(int a)
cout&&"receiver2: "&&a&&
};class sender
sender(): m_value(0)
int get_value()
void set_value(int new_value)
if (new_value!=m_value)
m_value=new_
m_sig(new_value);
signal&receiver,int& m_private:
};int main(int argc,char** arg)
s.m_sig.bind(&r,&receiver::callback1);
s.m_sig.bind(&r,&receiver::callback2);
s.set_value(1);
程序在VC6下顺利通过,这个版本相比前面所说的继承手法耦合性低了,被调用者receiver与规定函数接口的slot类没有任何关系,但仔细以观察这个程序在概念上是有问题的,signal类有两个模板参数,一个是类的类型,一个是函数参数类型,如果把这个signal/slots组件提供出去,使用者如上面的sender类不免会有个疑虑:在实例化signal类型时,必须提供这两个模板参数,可是调用方事先哪就一定知道接收方(receiver)的类型呢,而且从概念上讲事件发送方与接收方只需遵循一个共同的函数接口就可以了,与类没什么关系,上个程序要求在实例化时就得填充receiver的类型,也就决定了它与receiver只能一对一,而不能一对多,于是作此改进:将signal的参数T去掉,将T类型的推导延迟到绑定(bind)时,signal没有参数T,signal的成员slot也就不能有,那slot的成员也就不能有,可是,参数T总得找个地方落脚啊,怎么办?有个窍门:让slot包含slotbase成员,slotbase没有参数T的,但slotbase只定义接口,真正的实现放到slotimpl中,slotimpl就可以挂上参数T了,boost中any、shared_ptr就是用此手法,改进后全部代码如下:
#include &vector&
#include &iostream&using namespace
template&typename T1&class slotbase
virtual void Execute(T1 para)=0;
template&typename T,typename T1&class slotimpl : public slotbase&T1&
slotimpl(T* pObj,void (T::*pMemberFunc)(T1))
m_pMemberFunc=pMemberF
virtual void Execute(T1 para)
(m_pObj-&*m_pMemberFunc)(para);
void (T::*m_pMemberFunc)(T1);
template&typename T1&class slot
template&typename T&
slot(T* pObj,void (T::*pMemberFunc)(T1))
m_pSlotbase=new slotimpl&T,T1&(pObj,pMemberFunc);
delete m_pS
void Execute(T1 para)
m_pSlotbase-&Execute(para);
slotbase&T1&* m_pS
template&typename T1&class signal
template&typename T&
void bind(T* pObj,void (T::*pMemberFunc)(T1 para))
m_slots.push_back(new slot&T1&(pObj,pMemberFunc));
vector&slot&T1&* &::iterator ite=m_slots.begin();
for (;ite!=m_slots.end();ite++)
void operator()(T1 para)
vector&slot&T1&* &::iterator ite=m_slots.begin();
for (;ite!=m_slots.end();ite++)
(*ite)-&Execute(para);
vector&slot&T1&* & m_
};#define CONNECT(sender,signal,receiver,slot)
sender.signal.bind(receiver,slot)class receiver
void callback1(int a)
cout&&"receiver1: "&&a&&
};class receiver2
void callback2(int a)
cout&&"receiver2: "&&a&&
};class sender
sender(): m_value(0)
int get_value()
void set_value(int new_value)
if (new_value!=m_value)
m_value=new_
m_valueChanged(new_value);
signal&int& m_valueCprivate:
};int main(int argc,char** arg)
receiver2 r2;
CONNECT(s,m_valueChanged,&r,&receiver::callback1);
CONNECT(s,m_valueChanged,&r2,&receiver2::callback2);
s.set_value(1);
这个版本就比较像样了,一个signal可与多个slots连接,增加了类似QT的connect,用宏实现#define CONNECT(sender,signal,receiver,slot) sender.signal.bind(receiver,slot),这样使用者就非常方便,而且现在已完全解耦,sender只管定义自己的signal,在恰当时机用仿函数形式调用即可,而receiver只管实现callback,互不影响,可独立工作,如果需要再通过CONNECT将它们连接起来即可,已经很组件化了,可是离真正的工程应用尚有一段距离,如它不能接收全局函数或静态成员函数或仿函数为回调函数,不能带两个或更多的函数参数,最后一步了。
boost之function
4、boost pdf
之function signal
5、 之delegate,by 管景伟
C++回调机制的几种实现方式
Callback的本质是设置一个函数指针进去,然后在需要触发某个事件时调用该方法, 比如Windows的窗口消息处理函数就是这种类型。
比如下面的示例代码,我们在...
回调函数应用实例:
1、定义一个Person类 (Person.h)文件:
注意:在这个类中指定了回调函数,回调函数的执行者,和回调函数指针
回调函数和回调函数指针是怎么关联的?
...
今天讨论下C/C++中的回调函数。
在理解&回调函数&之前,首先讨论下函数指针的概念。
(1)概念:指针是一个变量,是用来指向内存地址的。一个程序运行时,所...
C++回调接口
*版权证明: 只允许上传png/jpeg/jpg/gif格式的图片,且小于3M
*详细原因:
交 &em&C%2B%2B&/em&图像处理编程 3积分 立即下载 ...
&em&C%2B%2B&/em& C++ 常用例程源代码 lvxinliang上传 本资源包括67个C++教学中常用的例程的源代码,非常适合初学者参考学习。资源积分:1分 下载次数:10次 ...
从零开始实现信号槽机制:一
我们从一个具体的问题入手:“现在有一堆按钮,用来控制一堆电器,它们之间可能是一对多,也可能是多对一,如何设计这个结构?”这里有个形象的图:为了实现组件间的控制,我们很容易想到“回调函数”,对于C++开...
C++实现委托机制(一)
如果你接触过C#,你就会觉得C#中的delegate(委托)十分灵巧,它的用法上和C\C++的函数指针很像,但是却又比C\C++的函数指针更加灵活。并且委托可以一对多,也就是可以注册多个函数,甚至是某...
C++回调机制实现(转)
(1)Callback方式
Callback的本质是设置一个函数指针进去,然后在需要需要触发某个事件时调用该方法, 比如Windows的窗口消息处理函数就是这种类型。
比如下面的示例代码,我们...
没有更多推荐了,C++中实现回调机制的几种方式(一共三种方法_百度知道
C++中实现回调机制的几种方式(一共三种方法
答题抽奖
首次认真答题后
即可获得3次抽奖机会,100%中奖。
若以下回答无法解决问题,邀请你更新回答
比如下面的示例代码,我们在Download完成时需要触发一个通知外面的事件:typedef void (__stdcall *DownloadCallback)(const char* pURL, bool bOK);void DownloadFile(const char* pURL, DownloadCallback callback){
cout && &downloading: & && pURL && && &&
callback(pURL, true);}void __stdcall OnDownloadFinished(const char* pURL, bool bOK)
本回答被网友采纳
1条折叠回答
为你推荐:
其他类似问题
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。(1)Callback方式Callback的本质是设置一个函数指针进去,然后在需要需要触发某个事件时调用该方法, 比如Windows的窗口消息处理函数就是这种类型。比如下面的示例代码,我们在Download完成时需要触发一个通知外面的事件:
typedef&void&(__stdcall&*DownloadCallback)(const&char*&pURL,&bool&bOK);void&DownloadFile(const&char*&pURL,&DownloadCallback&callback){&&&&cout&&&&"downloading:&"&&&&pURL&&&&""&&&&&&&&callback(pURL,&true);}void&__stdcall&OnDownloadFinished(const&char*&pURL,&bool&bOK){&&&&cout&&&&"OnDownloadFinished,&URL:"&&&&pURL&&&&"&&&&status:"&&&&bOK&&&&}
(2)Sink方式Sink的本质是你按照对方要求实现一个C++接口,然后把你实现的接口设置给对方,对方需要触发事件时调用该接口, COM中连接点就是居于这种方式。上面下载文件的需求,如果用Sink实现,代码如下:
class&IDownloadSink{public:&&&&virtual&void&OnDownloadFinished(const&char*&pURL,&bool&bOK)&=&0;};class&CMyDownloader{public:&&&&CMyDownloader(IDownloadSink*&pSink)&&&&&&&&:m_pSink(pSink)&&&&{&&&&}&&&&void&DownloadFile(const&char*&pURL)&&&&{&&&&&&&&cout&&&&"downloading:&"&&&&pURL&&&&""&&&&&&&&&&&&if(m_pSink&!=&NULL)&&&&&&&&{&&&&&&&&&&&&m_pSink-&OnDownloadFinished(pURL,&true);&&&&&&&&}&&&&}private:&&&&IDownloadSink*&m_pS};class&CMyFile:&public&IDownloadSink{public:&&&&void&download()&&&&{&&&&&&&&CMyDownloader&downloader(this);&&&&&&&&downloader.DownloadFile("www.baidu.com");&&&&}&&&&virtual&void&OnDownloadFinished(const&char*&pURL,&bool&bOK)&&&&{&&&&&&&&cout&&&&"OnDownloadFinished,&URL:"&&&&pURL&&&&"&&&&status:"&&&&bOK&&&&&&&&}};
(3)Delegate方式Delegate的本质是设置成员函数指针给对方,然后让对方在需要触发事件时调用。C#中用Delegate的方式实现Event,让C++程序员很是羡慕,C++中因为语言本身的关系,要实现Delegate还是很麻烦的。上面的例子我们用Delegate的方式实现如下:&
class&CDownloadDelegateBase{public:&&&&virtual&void&Fire(const&char*&pURL,&bool&bOK)&=&0;};template&typename&O,&typename&T&class&CDownloadDelegate:&public&CDownloadDelegateBase{&&&&typedef&void&(T::*Fun)(const&char*,&bool);public:&&&&CDownloadDelegate(O*&pObj&=&NULL,&Fun&pFun&=&NULL)&&&&&&&&:m_pFun(pFun),&m_pObj(pObj)&&&&{&&&&}&&&&&&&&virtual&void&Fire(const&char*&pURL,&bool&bOK)&&&&{&&&&&&&&if(m_pFun&!=&NULL&&&&&&&&&&&&&&&m_pObj&!=&NULL)&&&&&&&&{&&&&&&&&&&&&(m_pObj-&*m_pFun)(pURL,&bOK);&&&&&&&&}&&&&}private:&&&&Fun&m_pF&&&&O*&m_pO};template&typename&O,&typename&T&CDownloadDelegate&O,T&*&MakeDelegate(O*&pObject,&void&(T::*pFun)(const&char*&pURL,&bool)){&&&&return&new&CDownloadDelegate&O,&T&(pObject,&pFun);}class&CDownloadEvent{public:&&&&~CDownloadEvent()&&&&{&&&&&&&&vector&CDownloadDelegateBase*&::iterator&itr&=&m_arDelegates.begin();&&&&&&&&while&(itr&!=&m_arDelegates.end())&&&&&&&&{&&&&&&&&&&&&delete&*&&&&&&&&&&&&++&&&&&&&&}&&&&&&&&m_arDelegates.clear();&&&&}&&&&void&operator&+=&(CDownloadDelegateBase*&p)&&&&{&&&&&&&&m_arDelegates.push_back(p);&&&&}&&&&void&operator&-=&(CDownloadDelegateBase*&p)&&&&{&&&&&&&&ITR&itr&=&remove(m_arDelegates.begin(),&m_arDelegates.end(),&p);&&&&&&&&ITR&itrTemp&=&&&&&&&&&while&(itrTemp&!=&m_arDelegates.end())&&&&&&&&{&&&&&&&&&&&&delete&*&&&&&&&&&&&&++&&&&&&&&}&&&&&&&&m_arDelegates.erase(itr,&m_arDelegates.end());&&&&}&&&&void&operator()(const&char*&pURL,&bool&bOK)&&&&{&&&&&&&&ITR&itrTemp&=&m_arDelegates.begin();&&&&&&&&while&(itrTemp&!=&m_arDelegates.end())&&&&&&&&{&&&&&&&&&&&&(*itrTemp)-&Fire(pURL,&bOK);&&&&&&&&&&&&++itrT&&&&&&&&}&&&&}private:&&&&vector&CDownloadDelegateBase*&&m_arD&&&&typedef&vector&CDownloadDelegateBase*&::iterator&ITR;};class&CMyDownloaderEx{public:&&&&void&DownloadFile(const&char*&pURL)&&&&{&&&&&&&&cout&&&&"downloading:&"&&&&pURL&&&&""&&&&&&&&&&&&downloadEvent(pURL,&true);&&&&}&&&&CDownloadEvent&downloadE};class&CMyFileEx{public:&&&&void&download()&&&&{&&&&&&&&CMyDownloaderEx&&&&&&&&&downloader.downloadEvent&+=&MakeDelegate(this,&&CMyFileEx::OnDownloadFinished);&&&&&&&&downloader.DownloadFile("www.baidu.com");&&&&}&&&&virtual&void&OnDownloadFinished(const&char*&pURL,&bool&bOK)&&&&{&&&&&&&&cout&&&&"OnDownloadFinished,&URL:"&&&&pURL&&&&"&&&&status:"&&&&bOK&&&&&&&&}};
可以看到Delegate的方式代码量比上面其他2种方式大多了,并且我们上面是固定参数数量和类型的实现方式,如果要实现可变参数,要更加麻烦的多。可变参数的方式可以参考这2种实现:我们可以用下面的代码测试我们上面的实现:
int&_tmain(int&argc,&_TCHAR*&argv[]){&&&&DownloadFile("www.baidu.com",&OnDownloadFinished);&&&&CMyFile&f1;&&&&f1.download();&&&&CMyFileEx&&&&&ff.download();&&&&system("pause");&&&&return&0;}
最后简单比较下上面3种实现回调的方法:第一种Callback的方法是面向过程的,使用简单而且灵活,正如C语言本身。第二种Sink的方法是面向对象的,在C++里使用较多, 可以在一个Sink里封装一组回调接口,适用于一系列比较固定的回调事件。第三种Delegate的方法也是面向对象的,和Sink封装一组接口不同,Delegate的封装是以函数为单位,粒度比Sink更小更灵活。&你更倾向于用哪种方式来实现回调?
http://www.cnblogs.com/weiym/archive//2660053.html
楼主的文章放在08年以前发表还可以读读,技术在进步,楼主没有进步。介绍两种方式1.__event/__raise/__hook 机制(微软自己扩展),和C#的event同样用法。2.C++ 0x11支持的lambda表达式和function类,可以替代一切回调。 我现在基本用这种方法。
3.如果不能使用c++11的话还可以是用boost中的function的吧
Views(...) Comments()c++ 异步处理
不久前自己参与了一个项目,其中有一个模块就是数据变化上送需要对tableview的数据进行更新。数据何时变化我并不知道,因此需要用到回调函数,当有数据变化的时候,调用回调函数执行数据变化上送的处理。
数据结构如下:
typedef struct user_callback_fun
/* 变化数据上送处理 */
int (*U_dataChangeFun)(RtuInfo *rtuInfo,int num);
} UserCallbackF
typedef struct user_data_init
IpPort pIpPort[MAX_RTU_NUM];
UserCallbackFun pUserC
}UserDataI
在程序里需要对回调函数进行注册,如下代码:
static int DataChange::UserDataChangeFunc(RtuInfo *rtuInfo, int num);//回调函数的声明
uDataInit.pUserCallback.U_dataChangeFun = DataChange::UserDataChangeF
注册好回调函数之后,当有数据变化时,利用UserDataInit结构体里的函数指针U_dataChangeFun调用回调函数即可。
异步处理需要考虑到数据的一致性,在特定的场合下需要运用到锁的技术。
c++11异步编程
c++11异步编程
C++11 异步方法
C++11 提供了几种异步调用的方法,都能通过std::future来获取异步执行的结果。
1. std::promise 可以用来在线程间提供数据传递。std::future = std::pro...
C++中的异步操作
实际上,C++11中对异步的支持不必Python和JavaScript弱,就是有点长。#include
c++中的异步和同步机制
关于异步和同步到底什么意思?一开始时有人问起来,不解,后来自己总结资料,弄明白在这里给大家分享:
异步:发起请求后,不等待这个发起的请求返回任何响应就去先干别的事,当然最后是等待到这个返回呢...
C++ 异步回调
上一文中讲了C语言通过函数指针实现异步回调
本文继续讨论C++中实现回调,由于C++中有类,而C语言中的回调函数不能直接定义为成员函数,所以就很麻烦了,下面将讨论解决办法。
首先知道静态成员函数是...
&em&C%2B%2B&/em& C++ 常用例程源代码
上传大小:43KB C++源代码算法 分享 本资源包括67个C++教学中常用的例程的源代码,非常适合初学者参考学习。...
C++ 实现同步异步定时器,不足之处请不吝赐教!
*版权证明: 只允许上传png/jpeg/jpg/gif格式的图片,且小于3M
*详细原因:
交 &em&C%2B%2B&/em&图像处理编程 3积分 立即下载 ...
RocketMQ提供了强大的消息系统功能,RocketMQ提供了java客户端,可以提供使用。下面代码来自RocketMQ4.0.0中的example代码。
Producer消息生产端:
【迷你书】&em&C%2B%2B&/em&程序设计原理与实践(&em&C%2B%2B&/em&之...Windows API&em&函数&/em&大全 立即下载
上传者: c51ram 时间...你的996,可能是给公司无能的&em&管理&/em&背锅
一夜暴富? ...
没有更多推荐了,}

我要回帖

更多关于 回调买入法 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信