多态问题的请教?

 
多态问题的请教? [已结帖,结帖人:yaoike]
进入用户个人空间
加为好友
发送私信
在线聊天
  • yaoike
  • 等级:
  • 可用分等级:
  • 总技术分:
  • 总技术分排名:
  • 结帖率:
发表于:2007-10-28 12:03:50 楼主
大家好,想请教大家一个方法的设计问题?谢谢你的解答。
我有几个类,如下:

class CMessage
{
  public:
    int m_nMessageId;
};

class CAuthMsg : public CMessage
{
  public:
    int m_nProdId;
};

class CTrafficAccoutMsg : public CMessage
{
  public:
    int m_nProdId;
};

class CProcessMsg
{
  public:
    void processMsg(CMessage *pMsg);
};

现在问题是,我如何实现processMsg()这个方法,让该方法可以识别调用该方法时,实参传进来的是CTrafficAccoutMsg指针还是CAuthMsg指针,然后对它们进行一系列的处理后,再返回指针,请问我该如何设计这个方法,我希望把它设置成通用一点。谢谢指教!

void CProcessMsg::processMsg(CMessage *pMessage)
{
    switch (pMessage->m_nMessageId)
    {
      case ID_Auth:
        CAuthMsg *pMsg = new CAuthMsg;
        ... // 这里对CAuthMsg对象指针pMsg的数据成员m_nProdId 进行一系列的处理. 例如这句:pMsg->m_nProdId = 8;
        break;
      case ID_TrafficAccout:
        CTrafficAccoutMsg *pMsg = new CTrafficAccoutMsg;
        ... // 这里对CTrafficAccoutMsg 对象指针pMsg的数据成员m_nProdId 也进行一系列的处理.例如都是这句:
            // pMsg->m_nProdId = 8;因为处理与上面的处理相同,我希望把这一块单独提取出来,请问我该如何做?
        break;
      default:
        break;
    }
    // 如果把 pMsg->m_nProdId = 8;这句放在这里的话,就跳出了 pMsg指针的作用域,我在这个问题上想了一两天,都想不
    // 出一个头绪来,各位可以指点一下吗?注:因为类已经封装好,所以,暂时不考虑把 m_nProdId 放到 类CMessage中。请
    // 在保持现有类结构的情况下,把这个方法的实现改写一下可以吗?至于这个方法processMsg()的形参个数,返回值等都可
  //  以自由定义。非常感谢!!!
}


100  修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • fetag
  • 等级:
  • 可用分等级:
  • 总技术分:
  • 总技术分排名:
发表于:2007-10-28 12:17:431楼 得分:5
可以用 typeid 来实现:

C/C++ code
           
           
if ( typeid(tmp) == typeid(CTrafficAccoutMsg) ) { // received a CTrafficAccoutMsg object; } else { // not a CTrafficAccoutMsg object, is a CAuthMsg object; }
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • wanfustudio
  • 等级:
  • 可用分等级:
  • 总技术分:
  • 总技术分排名:
  • 2

    2

发表于:2007-10-28 12:21:412楼 得分:0
这个多态不行吗?
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • wanfustudio
  • 等级:
  • 可用分等级:
  • 总技术分:
  • 总技术分排名:
  • 2

    2

发表于:2007-10-28 12:23:453楼 得分:12
C/C++ code
           
           
#include < iostream > using namespace std; class CMessage { public : int m_nMessageId; virtual void processMsg() = 0 ; }; class CAuthMsg : public CMessage { public : int m_nProdId; void processMsg() { cout << " auth<< " << endl; } }; class CTrafficAccoutMsg : public CMessage { public : int m_nProdId; void processMsg() { cout << " traffic<< " << endl; } }; class CProcessMsg { public : void processMsg(CMessage * pMsg) { pMsg -> processMsg(); } }; int main( int argc , char * argv[]) { CTrafficAccoutMsg tm; CAuthMsg am; CProcessMsg cpm; cpm.processMsg( & tm); cpm.processMsg( & am); return 0 ; }
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • ilovevvv
  • 等级:
  • 可用分等级:
  • 总技术分:
  • 总技术分排名:
发表于:2007-10-28 12:35:584楼 得分:12
看不太明白lz需要什么..
要在processMsg里面统一处理m_nProdId??
C/C++ code
           
           
class CMessage { public : void ProcessProdID() { ProcessProdID_Helper(); } int m_nMessageId; protected : virtual void ProcessProdID_Helper() = 0 ; }; class CAuthMsg : public CMessage { public : int m_nProdId; private : virtual void ProcessProdID_Helper() { printf( " CAuthMsg Proecess m_nProdId/n " ); } }; class CTrafficAccoutMsg : public CMessage { public : int m_nProdId; private : virtual void ProcessProdID_Helper() { printf( " CTrafficAccoutMsg Proecess m_nProdId/n " ); } }; class CProcessMsg { public : void processMsg(CMessage * pMsg) { // 通用处理m_ProdId???? pMsg -> ProcessProdID(); } };
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • thecorr
  • 等级:
  • 可用分等级:
  • 总技术分:
  • 总技术分排名:
发表于:2007-10-28 12:38:275楼 得分:1
龙女的 和工作室的想法都很好。

偶只有赞叹的份了
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • ckt1120
  • 等级:
  • 可用分等级:
  • 总技术分:
  • 总技术分排名:
发表于:2007-10-28 12:46:016楼 得分:5
像wanfustudio 说的

设计个虚函数,在子类中再去写你像实现的
如果是都是相同的操作,就在子类中添加一个非虚函数,
统一调用接口处理

修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • xlbdan
  • 等级:
  • 可用分等级:
  • 总技术分:
  • 总技术分排名:
发表于:2007-10-28 12:52:537楼 得分:5
3楼和4楼的方法都可以完成楼主的要求了

3楼是传统的虚函数做法

4楼是用非虚函数接口来做的

看楼主想要哪个了
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • zhangyanli
  • 等级:
  • 可用分等级:
  • 总技术分:
  • 总技术分排名:
发表于:2007-10-28 13:14:138楼 得分:10
pMsg- >m_nProdId = 8;因为处理与上面的处理相同,我希望把这一块单独提取出来,请问我该如何做?
----------
楼主可以把对m_nprodid的处理作成一个非虚函数放到基类里面,作成protected,然后让子类继承.然后用
3楼的方法在子类的virtual void processMsg() = 0;实现过程中调用该方法.即可实现统一处理.
代码如下:/
C/C++ code
           
           
#include < iostream > using namespace std; class CMessage { public : int m_nMessageId; virtual void processMsg() = 0 ; protected : void processid( int id) // 因为要做统一处理,所以不用写成虚函数,子类直接继承即可。 { m_nProdId = 8 ; 。。。。。。 。。。。。。 // 要做的统一处理 } }; class CAuthMsg : public CMessage { public : int m_nProdId; void processMsg() { cout << " auth<< " << endl; processid(m_nProdId); // 子类中调用processid函数。也可写到基类中 } }; class CTrafficAccoutMsg : public CMessage { public : int m_nProdId; void processMsg() { cout << " traffic<< " << endl; } }; class CProcessMsg { public : void processMsg(CMessage * pMsg) { pMsg -> processMsg(); } }; int main( int argc , char * argv[]) { CTrafficAccoutMsg tm; CAuthMsg am; CProcessMsg cpm; cpm.processMsg( & tm); cpm.processMsg( & am); return 0 ; }


修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • zhangyanli
  • 等级:
  • 可用分等级:
  • 总技术分:
  • 总技术分排名:
发表于:2007-10-28 13:15:169楼 得分:0
上面是大概的思路,楼主改一下即可。
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • yaoike
  • 等级:
  • 可用分等级:
  • 总技术分:
  • 总技术分排名:
发表于:2007-10-28 13:29:1910楼 得分:0
谢谢大家这么热心解答,大家都是人才啊~~~ 一下子就回复过来了。。。 (实际上还是自己水平太次了吧),非常感谢你们的帮忙。

我先简单回复一下大家:其实我的意思就是说,如何在一个函数里面针对不同的对象(形参)进行统一的处理。

1. TO fetag:可能是我的意思表达不清,你可能理解错了。你的意思是说:
if ( typeid(tmp) == typeid(CTrafficAccoutMsg) )
{
    //received a CTrafficAccoutMsg object;
}
else
{
    //not a CTrafficAccoutMsg object, is a CAuthMsg object;
}

我的提问是:在接下来的处理中,无论是 CTrafficAccoutMsg,还是CAuthMsg,都对它的数据成员m_nProdId进行统一的处理,请问,我该如何做呢?非常感谢你的光临~

To wanfustudio,ilovevvv:
    你们的方法很好,非常感谢,我的问题按照你们的方法可以解决,请问,还可以用其它的方法吗?


To ckt1120:
    非常感谢你的指点,如果是都是相同的操作,就在子类中添加一个非虚函数,统一调用接口处理 ,那我的情况是希望无论是CAuthMsg类,或是CTrafficAccoutMsg 类,都对它们的数据成员 m_nProdId 进行统一的处理,但是数据成员 m_nProdId 又不可以放在基类 CMessage 中,请问,我该如何写这个非虚函数呢?这样的话,是不是同样的处理,都必须在 CAuthMsg 类 和 CTrafficAccoutMsg 类 中分别写上非虚函数了吗? 

To xlbdan:
    非常感谢你的再次说明,我对这两种实现的优点和缺点不太了解,传统的虚函数在什么情况下用比较合适一点,而非虚函数接口又比较适合于用在什么地方呢?谢谢~~~


修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • fetag
  • 等级:
  • 可用分等级:
  • 总技术分:
  • 总技术分排名:
发表于:2007-10-28 13:37:4811楼 得分:5
OK!

class Base{};

class First: public Base{
public:
    void one();
};

class Second: public Base
{
public:
    void two();
};

......

void fun(Base* b)    //基类的指针可以指向派生类的对象,所以此处可以接受以上三个类型的参数
{
    if ( typeid(b) == typeid(Base) )
    {
        //received a Base object;
    }
    else if ( typeid(b) == typeid(First) )
    {
        //received a First object;
    }
    else if ( typeid(b) == typeid(Second) )
    {
        //received a Second object;
    }   
}

你要是看懂上面的代码,就知道我说的能不能实现你要的功能了。
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • Chiyer
  • 等级:
  • 可用分等级:
  • 总技术分:
  • 总技术分排名:
  • 4

    4

    3

发表于:2007-10-28 13:47:4812楼 得分:0
C/C++ code
           
           
void CProcessMsg::processMsg(CMessage * pMessage) { CMessage pMessage = 0 ; switch (pMessage - > m_nMessageId) { case ID_Auth: CAuthMsg * pMsg = new CAuthMsg; pMessage = pMsg; break ; case ID_TrafficAccout: CTrafficAccoutMsg * pMsg = new CTrafficAccoutMsg; pMessage = pMsg; break ; default : break ; } pMessage - > m_nProdId = 8 ; }
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • Chiyer
  • 等级:
  • 可用分等级:
  • 总技术分:
  • 总技术分排名:
  • 4

    4

    3

发表于:2007-10-28 13:49:0113楼 得分:10
C/C++ code
           
           
void CProcessMsg::processMsg(CMessage * pMessage) { CMessage * pMessage = 0 ; switch (pMessage - > m_nMessageId) { case ID_Auth: CAuthMsg * pMsg = new CAuthMsg; pMessage = pMsg; break ; case ID_TrafficAccout: CTrafficAccoutMsg * pMsg = new CTrafficAccoutMsg; pMessage = pMsg; break ; default : break ; } pMessage -> m_nProdId = 8 ; }
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • sookzeng
  • 等级:
  • 可用分等级:
  • 总技术分:
  • 总技术分排名:
发表于:2007-10-28 13:52:4314楼 得分:5
注:因为类已经封装好,所以,暂时不考虑把 m_nProdId 放到 类CMessage中。请
    在保持现有类结构的情况下,把这个方法的实现改写一下可以吗?

---------------------------------------------
lz要求是只能改函数实现啊!那只有把那些相同的代码放到一个独立的函数中处理咯,把要改的参数都传进去(怪怪的:))。

不过还是建议楼主把这种共有的成员抽取到基类中,以基类的统一方法修改。

如果需要在不同派生类中作不同处理,则采用楼上的虚函数的建议吧  :)
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • xlbdan
  • 等级:
  • 可用分等级:
  • 总技术分:
  • 总技术分排名:
发表于:2007-10-28 14:11:2415楼 得分:5
非常感谢你的再次说明,我对这两种实现的优点和缺点不太了解,传统的虚函数在什么情况下用比较合适一点,而非虚函数接口又比较适合于用在什么地方呢?谢谢~~~


其实这两种实现方法的本质都是一样的,只不过后者把前者用一个非虚函数来封装了一下,一般情况下两者都是可以通用的
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • sookzeng
  • 等级:
  • 可用分等级:
  • 总技术分:
  • 总技术分排名:
发表于:2007-10-28 14:59:3216楼 得分:5
传统的虚函数在什么情况下用比较合适一点,而非虚函数接口又比较适合于用在什么地方呢?
=======================

虚函数用于符合虚函数应用场景的场合 :), 否则,为了提高函数调用效率,不要用虚函数。

至于场景?简单的说,比如当要求写一个函数,它只需接受一个通用参数(基类指针或引用),并可以针对不同的传入类型作不同的处理,而且处理代码只有一句,而不用像lz那样费力的switch。这唯一一句代码写成虚函数的调用即可。

但对于lz后来说到的所有派生类共用的代码,建议以常规函数写在基类中,再在派生类的虚函数中调用吧  :)
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • CQZE
  • 等级:
  • 可用分等级:
  • 总技术分:
  • 总技术分排名:
发表于:2007-10-28 16:06:5017楼 得分:5
Visitor吧

CProcessMsg的动作放在CMessage里面不科学吧。
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • dy_david
  • 等级:
  • 可用分等级:
  • 总技术分:
  • 总技术分排名:
发表于:2007-10-28 16:35:3718楼 得分:1
雁南飞工作室
正解
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • yaoike
  • 等级:
  • 可用分等级:
  • 总技术分:
  • 总技术分排名:
发表于:2007-10-28 17:43:2819楼 得分:0
谢谢大家这么关注这个问题,非常感谢!!!

To sookzeng : 多谢解答,你说的: “但对于lz后来说到的所有派生类共用的代码,建议以常规函数写在基类中,再在派生类的虚函数中调用吧  :)” 我也希望这样做,可是,现在的情况是: 派生类都共有一个数据成员: m_nProdId, 可是,这个共有的数据成员m_nProdId 不可以放在基类 CMessage 里面,我以常规函数写在基类里面,却无法对它的派生类的数据成员 m_nProdId 进行操作处理。 但是,如果我像 wanfustudio,ilovevvv 兄那样分别在派生类里面写虚函数的话,处理却都是相同的,没有做到通用性,请问,像这种情况大家还有没有其它的处理办法呢?
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • yaoike
  • 等级:
  • 可用分等级:
  • 总技术分:
  • 总技术分排名:
发表于:2007-10-28 17:53:3720楼 得分:0

To fetag, Chiyer: 非常感谢,很抱歉我还是没能完整表达我的意思,嗯,对了,我可以看懂你上面在11楼所写的代码。我原来上面的函数写少了一句,麻烦请再看以下的这个方法:

void CProcessMsg::processMsg(CMessage *pMessage)
{
    switch (pMessage- >m_nMessageId)
    {
      case ID_Auth:
        CAuthMsg *pMsg = new CAuthMsg;
        pMsg = (CAuthMsg*)pMessage;
        ... // 这里对CAuthMsg对象指针pMsg的数据成员m_nProdId 进行一系列的处理. 例如这句:pMsg- >m_nProdId = 8;
        break;
      case ID_TrafficAccout:
        CTrafficAccoutMsg *pMsg = new CTrafficAccoutMsg;
        pMsg = (CTrafficAccoutMsg*)pMessage
        ... // 这里对CTrafficAccoutMsg 对象指针pMsg的数据成员m_nProdId 也进行一系列的处理.例如都是这句:
          // pMsg- >m_nProdId = 8;因为处理与上面的处理相同,我希望把这一块单独提取出来,请问我该如何做?
        break;
      default:
        break;
    }
    // 如果把 pMsg- >m_nProdId = 8;这句放在这里的话,就跳出了 pMsg指针的作用域,我在这个问题上想了一两天,
    // 都想不出一个头绪来,各位可以指点一下吗?注:因为类已经封装好,所以,暂时不考虑把 m_nProdId 放到
    //  类CMessage中。请在保持现有类结构的情况下,把这个方法的实现改写一下可以吗?至于这个方法processMsg()
    // 的形参个数,返回值等都可以自由定义。非常感谢!!! 
  // 
}


   
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • Faitle
  • 等级:
  • 可用分等级:
  • 总技术分:
  • 总技术分排名:
发表于:2007-10-28 18:46:5421楼 得分:2
呵,可以用dynamic_cast <Derived>判断
如果转型不成功会返回NULL的
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • ilovevvv
  • 等级:
  • 可用分等级:
  • 总技术分:
  • 总技术分排名:
发表于:2007-10-28 19:20:2822楼 得分:9
lz的要求好奇怪...
既然数据和处理都一样,直接放在基类不就好了吗=.=
再贴一段,看看是不是能满足你的要求(这样做迟早会出事情的,好的技巧远远比不上好的设计,何况这个技巧还和好不搭边)
C/C++ code
           
           
class IMessage { public : virtual void ProcessProdID() = 0 ; }; template < typename T > class CMessage : public IMessage { public : void ProcessProdID() { T * pT = static_cast < T *> ( this ); pT -> m_nProdId = 8 ; } int m_nMessageId; }; class CAuthMsg : public CMessage < CAuthMsg > { public : int m_nProdId; }; class CTrafficAccoutMsg : public CMessage < CTrafficAccoutMsg > { public : int m_nProdId; }; class CProcessMsg { public : void processMsg(IMessage * pMsg) { // ....lz自己想干嘛干嘛 // 通用处理m_ProdId???? pMsg -> ProcessProdID(); } }; void main() { CTrafficAccoutMsg tm; CAuthMsg am; CProcessMsg cpm; cpm.processMsg( & tm); cpm.processMsg( & am); }
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • nevergone
  • 等级:
  • 可用分等级:
  • 总技术分:
  • 总技术分排名:
发表于:2007-10-28 21:24:1523楼 得分:3
我这看类问题最好的解法是:
1.用虚函数,也就是wanfustudio 的方法.
用一个ID来表示处理,不好扩展,代码维护起来很麻烦.这也是很多C++大师告诫我们不用要这样的方法
2.用ilovevvv的方法,ATL/WTL就是采用这种方法来避免虚函数开销
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • feitianmouse
  • 等级:
  • 可用分等级:
  • 总技术分:
  • 总技术分排名:
发表于:2007-10-29 10:21:2624楼 得分:0
mark
修改 删除 举报 引用 回复
进入用户个人空间
加为好友
发送私信
在线聊天
  • scq2099yt
  • 等级:
  • 可用分等级:
  • 总技术分:
  • 总技术分排名:
发表于:2007-10-30 09:35:2325楼 得分:0
ding
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值