« Shadow Map Demo2联结FBO与Texture Array »

成员函数指针使用小感

 今天整理代码的时候,早有预感地,要遇上成员函数指针的使用了。其实自从C语言开始,我对成员函数指针这东西还停留一知半解的阶段,惭愧ING。还好,今天对它的使用“手法”又多了点了解。使用成员函数指针使用小感。——ZwqXin.com

本文来源于 ZwqXin (http://www.zwqxin.com/), 转载请注明
      原文地址:http://www.zwqxin.com/archives/cpp/use-member-function-pointer.html

事情是这样的。我今天把CSM(Cascading Shadow Maps)的结构清理一下,虽然说只是单单把涉及CSM算法的代码抽出CMainFrame并不是什么真正的重构,但起码别让一堆代码堆挤在一起吧。一切单纯而懒散地进行着,终于来到了最后一个编译错误(最后一个要改的地方):

  1. //在CMainFrame中:
  2. //....
  3. CCascadingSM CascadingSM;//CSM对象
  4. //.....
  5. void CMainFrame::RenderObjects()
  6. {.....}
  7.  
  8. void CMainFrame::RenderGLScene()
  9. {
  10. .....
  11. CascadingSM.GenShadowMap(....);
  12. ......
  13. CascadingSM.CastShadowMap(....);
  14. }
  15. //-------------------------类间分割线-------------
  16. //在CCascadingSM中:
  17. void CCascadingSM::GenShadowMap(......)
  18. {
  19. ....
  20. ()  //-----本来放RenderObjects()的地方
  21. ....
  22. }
  23. void CCascadingSM::CastShadowMap(......)
  24. {
  25. ....
  26. ()  //-----本来放RenderObjects()的地方
  27. ....
  28. }

熟悉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个解决之道,但它里面介绍是同类间调用的,好吧,变通一下就可以了。

  1. //在CMainFrame中:
  2. //....
  3. CCascadingSM CascadingSM;//CSM对象
  4. //.....
  5. void CMainFrame::RenderObjects()
  6. {.....}
  7.  
  8. //重点:帮拖的全局辅助函数:
  9. void Help_RenderObjects(CMainFrame *mf)
  10. {
  11.     mf->RenderObjects();
  12. }
  13. //////
  14.  
  15. void CMainFrame::RenderGLScene()
  16. {
  17. .......
  18. CascadingSM.GenShadowMap(this, Help_RenderObjects....);
  19. .......
  20. CascadingSM.CastShadowMap(this, Help_RenderObjects);
  21. }
  22. //-------------------------类间分割线-------------
  23. //在CCascadingSM类中:
  24. class CMainFrame;//前置声明,写在类声明前头
  25. .....
  26. void CCascadingSM::GenShadowMap(CMainFrame *Mf,void (*scene)(CMainFrame *mf)...)
  27. {
  28. ....
  29. (*scene)(Mf);  //-----本来放RenderObjects()的地方
  30. ....
  31. }
  32. void CCascadingSM::CastShadowMap(CMainFrame *Mf,void (*scene)(CMainFrame *mf))
  33. {
  34. ....
  35. (*scene)(Mf);  //-----本来放RenderObjects()的地方
  36. ....
  37. }

先看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.com/), 转载请注明
      原文地址:http://www.zwqxin.com/archives/cpp/use-member-function-pointer.html

  • quote 1.dophi
  • 我以前也疑惑过非静态成员函数指针,推荐《深度探索C++对象模型》给你看,如果嫌看书麻烦,就网上搜下“c++对象模型”也够了。
  • 2010-9-3 15:30:10 回复该留言

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

IE下本页面显示有问题?

→点击地址栏右侧【兼容视图】←

日历

Search

网站分类

最新评论及回复

最近发表

Powered By Z-Blog 1.8 Walle Build 100427

Copyright 2008-2013 ZwqXin. All Rights Reserved. Theme edited from ipati.