发信人: girlrong() 
整理人: wenbobo(2002-12-06 23:08:29), 站内信件
 | 
 
 
    按照tengel和repus的提示,我用如下方法,总算将一个类对象里的函数指针 pFun指向了另一个类对象里的非静态成员函数GetResult(不过这个成员函数用的 是_stdcall调用协议),而且还能用这个函数指针来调用GetResult了。原来要改 变调用协议,不能用类成员函数默认的thiscall调用协议。但是还有个问题。     举个例子吧,我写一个类,例如叫CCommonClass,它开了一个某种类型的窗 口,当用鼠标双击了某个区域时,该类的鼠标消息处理函数将调用该类的一个函 数指针指向的一个外部类的成员函数,将坐标值传出去。为了使CCommonClass成 为一个通用的类,CCommonClass必须不知道这个外部类的类名,也不知道这个成 员函数的名字,所以得用函数指针实现。使用CCommonClass的人只需提供一个符 合要求的函数给CCommonClass类,记录在CCommonClass类的一个函数指针成员里 ,用来接收结果就可以了。
     假设在一个叫做CUserClass的类里使用CCommonClass类,非常遗憾的是在CCo mmonClass类里要引用CUserClass的类名和对象指针。而按照我的设想,为了使C CommonClass类成为通用的,事先不可能知道CUserClass的具体类型和类名,不可 能去引用CUserClass的类名和对象指针。这下完了,CCommonClass类必须知道CU serClass的类名,成不了通用的了。
      虽然CCommonClass可以给CUserClass发个通知消息,告诉结果,但这又要求 CUserClass要从CWnd类派生,所以想试试别的方法。
      源代码如下,恳请C++高手们指点。为了简单,把它改写成console程序了。
 
 
  #include <stdio.h> #define CALLBACK _stdcall
  class CUserClass;
  class CCommonClass {     //这就是想成为通用类的类。可是却不得不引用了CUserClass的类名 public:     CCommonClass();     void SetFunc(CUserClass*pu,void (CALLBACK CUserClass::*fun)(int a) );     void OnResult(); private:     void (CALLBACK CUserClass::*pFun)(int a);     CUserClass* pUserObject; }; void CCommonClass::SetFunc(CUserClass* pu,void (CALLBACK CUserClass::* fun)(int a)) {     //外部使用者CUserClass类对象就通过这个函数提供一个符合     //要求的用来接收结果的函数     pFun=fun;     pUserObject=pu; };
 
  CCommonClass::CCommonClass() {     pFun=NULL;pUserObject=NULL; }
  void CCommonClass::OnResult() {     //假设CCommonClass类有了结果后就在这里调用pFun所指向的函数     (pUserObject->*pFun)(3);//假设3就是结果。 } ///////////////////////////////////////// class CUserClass {     //假设这是任意一个使用CCommonClass类的类。     //按照设想,这个使用者的名字应该是任意的,     //但现在如果不叫CUserClass的话就无法使用CCommonClass类。 public:     CCommonClass CommonObject;     void DoWork();     void CALLBACK GetResult(int a); };
 
  void CUserClass::DoWork() {     //在这里向CCommonClass对象提供一个符合要求的函数     CommonObject.SetFunc(this,GetResult); }
  void CALLBACK CUserClass::GetResult(int a) {     //在CUerClass里接收CCommonClass的处理结果     printf("结果是:%d\n\n",a); }
  ////////////////////////////////////////////////
  int main()  {     CUserClass MyObject;     MyObject.DoWork();     MyObject.CommonObject.OnResult();//模拟获得了结果     return 1; } 
  -- ※ 来源:.月光软件站 http://www.moon-soft.com.[FROM: 202.103.244.5] 发信人: tengel (Dragon), 信区: CLanguage 标  题: Re: 难道就不能用这种方法编写通用类 发信站: 网易虚拟社区 (Sat Nov  6 09:30:28 1999), 站内信件
  【 在 girlrong (阿蓉) 的大作中提到: 】 看看MFC的CRunTimeClass怎么做的,虽然那样做很麻烦,但至少我 想已经达到了你的部分目的. 另外,RTTI能否实现你的目的呢?我想你可以试一试:typeid 和typename 两个关键字,使用模板.我现在没有时间,如果你能试出来, 可否告诉我?
  -- 独进小楼成一统,管他冬夏与春秋
  ※ 来源:.月光软件站 http://www.moon-soft.com.[FROM: 202.104.33.10] 发信人: supermario (Mario), 信区: CLanguage 标  题: Re: 难道就不能用这种方法编写通用类 发信站: 网易虚拟社区 (Sat Nov  6 16:42:27 1999), 站内信件
  【 在 girlrong (阿蓉) 的大作中提到: 】 看来阿蓉研究的问题已经很有深度了,真是三天不学习,赶不上阿蓉了, 对于C++我研究不深,说说我的想法吧,既然你这个类是用于供其他类 使用的,为什么不将它作为一个基类,由其他的类来继承呢?如果通过 这种函数指针的方式,总觉得容易破坏类的封装性。另外在定义函数时 ,好像可以通过宏定义的方式来定义参数,然后强迫类型转换,就象VC 里的Assert一样。 以前我用过这样的方式,不过是SDK形式,不知道C++中是否合法 宏定义: #define ALLOC_TABLE_HEAD(pTableHead,TableStruct)        \ {       \         if(!pTableHead){        \                 pTableHead = (TableStruct *)malloc(sizeof(TableStruct));\                 if (pTableHead == NULL)\                         return FALSE;\                 pTableHead->next = NULL;        \         }       \ } 引用宏: ALLOC_TABLE_HEAD(fav_long_date_head,fav_date)
  -----------------------------------------------------------             阿蓉,当心智商太高嫁不出去了,呵呵 -----------------------------------------------------------
  -- 点解啊,点解啊?   -- 捶胸蹬足状
  ※ 修改:.supermario 于 Nov  6 16:51:47 修改本文.[FROM: 202.102.171.135] ※ 来源:.月光软件站 http://www.moon-soft.com.[FROM: 202.102.171.135] 发信人: zelor (张作乐), 信区: CLanguage 标  题: Re: 难道就不能用这种方法编写通用类 发信站: 网易虚拟社区 (Sat Nov  6 19:06:24 1999), 站内信件
     哇,好过瘾,脑细胞好像进了一次健身房。只是小生我驽钝,看得我 一知半解。    P.S. 玛利,小心言多必失,万一被阿蓉点了哑穴可就…… 【 在 supermario (Mario) 的大作中提到: 】 -- 生活,就是理想加泡面。3m                   --------张作乐--'-<@ 送你一束玫瑰
  ※ 来源:.月光软件站 http://www.moon-soft.com.[FROM: 202.103.46.194] 发信人: zelor (张作乐), 信区: CLanguage 标  题: Re: 难道就不能用这种方法编写通用类 发信站: 网易虚拟社区 (Sat Nov  6 19:10:23 1999), 站内信件
     使用指向函数的指针确实有点破坏封装性,不过这个方法如果成功也是 可以更大程度的实现代码重用,倒也是OOP的原意嘛。 -- 冬雷滚滚夏雨雪, 山无棱,天地合, WINDOWS再没有BUG, 才敢与君绝!                            ———作乐的爱情格言    
  ※ 来源:.月光软件站 http://www.moon-soft.com.[FROM: 202.103.46.194] 发信人: girlrong (阿蓉), 信区: CLanguage 标  题: Re: 难道就不能用这种方法编写通用类 发信站: 网易 BBS (Sat Nov  6 19:44:09 1999), 转信
  【 在 supermario (Mario) 的大作中提到: 】     作为基类不符合要求。比如,如果这个类是个视图类,使用它的是框架窗口类, 总不能从这个视图类派生一个框架窗口类吧?使用这个视图类的还多了,还有文档。 他们都各是各的类,不好派生的。
  -- ※ 来源:.网易 BBS bbs.netease.com.[FROM: 202.103.243.27] 发信人: repus (Super), 信区: CLanguage 标  题: Re: 难道就不能用这种方法编写通用类 发信站: 网易虚拟社区 (Sat Nov  6 21:22:06 1999), 站内信件
  【 在 girlrong (阿蓉) 的大作中提到: 】 你再去看看,以他最普通的调用方式,还能访问他自己类里的成员吗? -- ※ 来源:.月光软件站 http://www.moon-soft.com.[FROM: 202.101.2.141] 发信人: girlrong (阿蓉), 信区: CLanguage 标  题: Re: 难道就不能用这种方法编写通用类 发信站: 网易虚拟社区 (Sun Nov  7 09:04:55 1999), 站内信件
  【 在 repus (Super) 的大作中提到: 】 你是说那个GetResult函数能不能调用同类里的别的成员函数吗?可以呀: void CALLBACK CUserClass::GetResult(int a) {     //在CUerClass里接收CCommonClass的处理结果     PrintOut(a); } void CUserClass::PrintOut(int a) {     printf("结果是:%d\n\n",a); }
      PrintOut()就是个普通的成员函数,虽然GetResult()是CALLBACK协议,但也 可以调用它。甚至这样也可以: void CALLBACK CUserClass::GetResult(int a) {     //在CUerClass里接收CCommonClass的处理结果     this->PrintOut(a); } void CUserClass::PrintOut(int a) {     printf("结果是:%d\n\n",a); }
      本类中别的成员函数也可以正常调用GetResult。
  -- ※ 来源:.月光软件站 http://www.moon-soft.com.[FROM: 202.103.243.31] 发信人: zelor (张作乐), 信区: CLanguage 标  题: Re: 难道就不能用这种方法编写通用类 发信站: 网易虚拟社区 (Sun Nov  7 20:31:23 1999), 站内信件
      阿蓉啊,你的问题让我头大了两天。迷迷糊糊的感觉忽然有个想法, 能不能用指向函数的指针的指针。(呵呵,我的感觉,想隐藏什么东西 就用指针)不过我是想不清楚了,只是瞎说一句,希望能给你提供点线索。 刚抄了你的源码回去继续想,我只求能从中学点东西啦。     P.S. CRAZYJAVA呢?怎么没看到你的意见?
  -- 生活,就是理想加泡面。                   --------张作乐--'-<@ 送你一束玫瑰
  ※ 来源:.月光软件站 http://www.moon-soft.com.[FROM: 202.103.46.194] 发信人: girlrong (阿蓉), 信区: CLanguage 标  题: Re: 难道就不能用这种方法编写通用类 发信站: 网易 BBS (Sun Nov  7 20:36:02 1999), 转信 谢谢zelor。我试试看。
  -- ※ 来源:.网易 BBS bbs.netease.com.[FROM: 202.103.243.8]
  | 
 
 
 |