今天整理代码的时候,早有预感地,要遇上成员函数指针的使用了。其实自从C语言开始,我对成员函数指针这东西还停留一知半解的阶段,惭愧ING。还好,今天对它的使用“手法”又多了点了解。使用成员函数指针使用小感。——ZwqXin.com
本文来源于 ZwqXin (http://www.zwqxin.cn/), 转载请注明
原文地址:http://www.zwqxin.cn/archives/cpp/use-member-function-pointer.html
事情是这样的。我今天把CSM(Cascading Shadow Maps)的结构清理一下,虽然说只是单单把涉及CSM算法的代码抽出CMainFrame并不是什么真正的重构,但起码别让一堆代码堆挤在一起吧。一切单纯而懒散地进行着,终于来到了最后一个编译错误(最后一个要改的地方):
- //在CMainFrame中:
- //....
- CCascadingSM CascadingSM;//CSM对象
- //.....
- void CMainFrame::RenderObjects()
- {.....}
- void CMainFrame::RenderGLScene()
- {
- .....
- CascadingSM.GenShadowMap(....);
- ......
- CascadingSM.CastShadowMap(....);
- }
- //-------------------------类间分割线-------------
- //在CCascadingSM中:
- void CCascadingSM::GenShadowMap(......)
- {
- ....
- () //-----本来放RenderObjects()的地方
- ....
- }
- void CCascadingSM::CastShadowMap(......)
- {
- ....
- () //-----本来放RenderObjects()的地方
- ....
- }
熟悉Shadow Map的朋友都知道,GenShadowMap和CastShadowMap就是Shadow Map算法的两步走(两个PASS),分别是光源视觉下对场景生成阴影贴图(深度图),以及把该深度图应用于正常场景中做深度比较以生成阴影。两个函数都需要对场景(也就是RenderObjects())进行渲染。但是场景RenderObjects不属于CSM算法的一部分,所以我不打算把它交给CCascadingSM类。再者它不大,所以我也不打算让它单独成类,还是把它留在CMainFrame好了。
我看网上一些图形学教程,都喜欢过程式设计,对抽象封装不怎么在意(也许是侧重点不同吧,它们的目的在于呈现图形学API使用,算法之类。但其实我一直觉得单纯图形学作品设计,用过程式思维是最快捷方便的),他们多把东西放一个CPP里搞掂。其实我今天没进行代码整理之前也就这样子了。不过也因此对C++类封装设计不怎么敏感,至于成员函数指针这东西.......
好吧,请原谅我,我以前的处理方法就是把要调用成员函数指针的类,整个static静态化......这样当然不太好,就为了一个成员函数指针把整个类,有辜无辜的都弄变态了。但是当时年少无知的我真的google不出其他解决之道了(现在看来是关键字不对?),乐呵呵地编译成功就继续其他的了。....当然这是个办法,但是这次我忧郁了,因为我面对的是直接的应用类CMainFrame,好吧,我是不敢这样做了。局部静态化呢?不懂,google出来,也不太想看。boost的mem_fun?当时用一次就头疼(VC6还得boost来除BUG呀)。还有一个方法,可以类成员函数里可以保留其他该类的变量啊函数,而且不怕继承那一套的:给个全局的辅助函数吧。
这里有些资料是关于这些方法的:C++指针直接调用类成员函数探讨 ,我正想用它的第3个解决之道,但它里面介绍是同类间调用的,好吧,变通一下就可以了。
- //在CMainFrame中:
- //....
- CCascadingSM CascadingSM;//CSM对象
- //.....
- void CMainFrame::RenderObjects()
- {.....}
- //重点:帮拖的全局辅助函数:
- void Help_RenderObjects(CMainFrame *mf)
- {
- mf->RenderObjects();
- }
- //////
- void CMainFrame::RenderGLScene()
- {
- .......
- CascadingSM.GenShadowMap(this, Help_RenderObjects....);
- .......
- CascadingSM.CastShadowMap(this, Help_RenderObjects);
- }
- //-------------------------类间分割线-------------
- //在CCascadingSM类中:
- class CMainFrame;//前置声明,写在类声明前头
- .....
- void CCascadingSM::GenShadowMap(CMainFrame *Mf,void (*scene)(CMainFrame *mf)...)
- {
- ....
- (*scene)(Mf); //-----本来放RenderObjects()的地方
- ....
- }
- void CCascadingSM::CastShadowMap(CMainFrame *Mf,void (*scene)(CMainFrame *mf))
- {
- ....
- (*scene)(Mf); //-----本来放RenderObjects()的地方
- ....
- }
先看CCascadingSM类,一般的函数指针调用是void (*scene)()这样的吧,这里给它一个参数CMainFrame *mf,因此GenShadowMap函数参数列表要再加个CMainFrame *Mf, 这样调用的时候就可以写(*scene)(Mf);了(该函数指针有多少个参数,就在GenShadowMap函数参数列表里再加多少个对应的变量)。好吧,这里的指针相当于回调函数,回调一个void类型的以CMainFrame对象为参的函数。
我们目的是要让它回调另一个类——CmainFrame的RenderObjects(),这就是成员函数指针调用。然而,直接来是不可以的,因为众所周知,你要获得另一个类里的函数的指针,起码得知道该类生成的某个具体对象的地址。只有具体的东西才有指针而言。那么——我们是要创建一个CmainFrame对象么?不行,一来建这种应用类的对象可是大工程啊,二来就是你建了,那里面的RenderObjects()也不是你要的RenderObjects()了——我要的是在OPENGL窗口里持续运行的CmainFrame类,获得它的办法,就是this指针。
Help_RenderObjects(CMainFrame *mf)是连接一切的小桥梁。它需要的正是一个CMainFrame类型的指针,出来的结果就是这个指针下的成员函数RenderObjects()。明朗起来了,给它this指针,它就给我我所需要的那个RenderObjects()。因此,CCascadingSM类的GenShadowMap函数回调它(参数:this,GenShadowMap)就得到RenderObjects(),注意全局函数或static化的函数是不需要具体对象的支持的。一切完好。
恩,现在我最关心的是:效率如何?也许跟它无关,但是,也不知道调整代码过程中哪里给我出的桩,FPS降低了!!
本文来源于 ZwqXin (http://www.zwqxin.cn/), 转载请注明
原文地址:http://www.zwqxin.cn/archives/cpp/use-member-function-pointer.html