精华区 [关闭][返回]

当前位置:网易精华区>>讨论区精华>>编程开发>>C/C++>>C、C++语言基础>>难道就不能用这种方法编写通用类

主题:难道就不能用这种方法编写通用类
发信人: 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]

[关闭][返回]