勤能补拙,Expter

成都游戏Coder,记录游戏开发过程的笔记和心得!

根据子类类型访问其特有操作

描述:
   一个常见遇到的解决方案,下面记录下来。
   1个功能模块,有一个简单的继承体系,基类假设为Base.
   然后通过一个接口,如何访问子类的特有操作?
  
   /// 外部提供一个下面接口:
   virutal   Base*  getBase()  const ;

  ///我们得到Base指针后,需要根据Base的类型进行特定的操作,
 
void  function(Base  *obj)
{
    
/// 由于obj只是Base基类指针

    BaseObj1 
* obj1;
    BaseObj2 
* obj2;

    
if ( obj1 = dynamic_cast<BaseObj1*>( obj )  )
    
{
        
/// to do
    }

    
else if ( obj2 = dynamic_cast<BaseObj2*>( obj ) )
    
{
        
/// to do
    }

    
else 
    
{
        
///  you get the idea
    }

}

BaseObj1  和 BaseObj2 都继承与Base基类,随着继承体系的扩大,那么if  else条件判断会长,是否有更高效的方式

解决方式:
   1.多态:常见而且简单的方式
       针对上面描述的问题,首先想到的是多态,基类写一个虚函数,每个之类重写此接口。
void function( Base  *obj )
{
   obj
->todo();
}

1)但是如果function函数的某个操作是free obj时,通过todo恐怕不合适。
2)可能有些子类型不关心不必要的接口但是也得写。
3)如果todo包含多个操作,则会让之类变得很庞大。

  2. visitor模式.
     那么同时得提供下面的操作接口:

     void visit(const BaseObj1& obj1 );
     
void visit(const BaseObj2& obj2 );

    
/// 如果有多个子类型的话,需要重写visit,此时fuction
   void function( Base  *obj )
   
{
        visit( obj );
   }


   1)同样多少Base子类得些多少 visit接口。
   2)还得倚靠多态类型转换调用特定的visit接口,因为obj还是Base* 类型,还得转换具体的类型。

 3.把所有操作绑定到类身上:
    1)定义针对每个Base子类操纵接口类
    2)Base所有子类型的保存需要操纵对象.
  
    Base类定义:

template < typename type>
class Base
{
public:
    
class Handle
    
{
    
public:
        Handle()
        
{
            Base
<type>::m_handlelist.push_back( this );
        }

        
virtual void todo( const type& tp)   = 0;
    }
;

public:
    
static void   todo(Base<type> * base)
    
{
        
for( std::list<Handle*>::iterator itr = m_handlelist.begin() ; 
             itr 
!= m_handlelist.end() ; itr ++ )
        
{
                   
/// 通过模板转换为制定具体类型,然后根据具体参数调用具体的接口
            (*itr)->todo( *(type*)base );
        }
  
    }
  
    
void  todo()
    
{
        type::todo( 
this );
    }


protected:
    typedef std::list
<Handle*>        listtype;
    
static  listtype                              m_handlelist;/// 声明为静态,所以当模板实例化的时候,会根据不同的类型存在多份数据。
}
;



   定义2子类:

class BaseObj1 : public Base< BaseObj1 >
{
 
//// 定义接口
}

class BaseObj1 : public Base< BaseObj1 >
{
///   定义接口
}



定义操作类型:

class DoHandle : public BaseObj1::Handle ,
                 
public BaseObj2::Handle                 
{
public:
    
virtual    void todo(const BaseObj1 & obj1)
    
{
        std::cout 
<<" baseobj1  m_type address " << std::endl;
        
/// obj1.print();
    }

    
virtual void todo(const BaseObj2 & obj2)
    
{
        std::cout 
<<" baseobj2 m_type address " << std::endl;
                
/// obj2.print();
    }

}
;


现在function接口变为下面了

template<typename type>
void  function( Base<type> * base)
{
        
base->todo();
}


调用方式:

BaseObj1  obj1;
BaseObj2  obj2;
DoHandle  handle;  
///绑定到obj1,obj2对象的m_handlelist列表中。
fun( & obj1 );
fun( 
& obj2 );



最后发现最后一个有点像Listener模式,-_-|||
总结完毕:

代码:
/Files/expter/test.rar

posted on 2011-02-24 23:23 expter 阅读(2139) 评论(4)  编辑 收藏 引用 所属分类: 其他学习笔记工作笔记生活笔记算法与数据结构

评论

# re: 根据子类类型访问其特有操作 2011-02-25 14:53 Kevin Lynx

我觉得就为了归纳一些共同接口,这样子做有点过了。不妨考虑在类设计时就将功能分出来。与其想尽办法保持类接口的数量不膨胀,倒不如让类的功能单一。简单的继承结构就够了。  回复  更多评论   

# re: 根据子类类型访问其特有操作 [未登录] 2011-02-25 16:36 ymc

我更倾向使用traits 和 基于tag的分派来实现这种效果,会简洁很多。  回复  更多评论   

# re: 根据子类类型访问其特有操作 2011-02-26 12:21 abettor

可以在Base类里定义一个专门用于访问子类特定方法的抽象方法,如:
virtual void * do_special(void * param) = 0;
在各个子类的实现里,不管其特定方法是什么,他们自己都可以通过实现do_special,并在其中调用那些方法而达到目的。  回复  更多评论   

# re: 根据子类类型访问其特有操作 2011-02-27 18:20 expter

@abettor
就是第一种方法。  回复  更多评论   


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理