読者です 読者をやめる 読者になる 読者になる

gl5_progのメモ

自分のためのメモとかまとめとか

C++でトレイトみたいなもの

http://ideone.com/6O3GTF

#include <stdio.h>

#define TRAIT_DEF( trait_name ) \
   class Trait_##trait_name \
   { \
    public: \
       virtual void trait_name( void ) = 0; \
   }
#define TRAIT_USE( trait_name, class_name ) \
   Trait_##trait_name##_##class_name m_Trait_##trait_name; \
    public: \
   Trait_##trait_name* GetTrait_##trait_name( void ){ return &m_Trait_##trait_name; } \
   friend class Trait_##trait_name##_##class_name
#define TRAIT_INIT( trait_name ) m_Trait_##trait_name(this)
#define TRAIT_HELPER_DEF( trait_name, class_name ) \
   class Trait_##trait_name##_##class_name : public Trait_##trait_name \
   { \
       class class_name* m_pTarget; \
    public: \
       Trait_##trait_name##_##class_name( class_name* p ) : m_pTarget( p ){} \
       virtual void trait_name( void ); \
   }
#define TRAIT_HELPER_DEF_AFTER( trait_name, class_name ) \
       void Trait_##trait_name##_##class_name::trait_name( void ) \
       { \
           m_pTarget->trait_name(); \
       }

TRAIT_DEF( Draw );
TRAIT_DEF( Update );
TRAIT_DEF( Jump );

TRAIT_HELPER_DEF( Draw, A );
TRAIT_HELPER_DEF( Update, A );
class A
{
    TRAIT_USE( Draw, A );
    TRAIT_USE( Update, A );
public:
    A() : TRAIT_INIT( Draw ), TRAIT_INIT( Update ){}
    void Draw( void ){ printf( "A::Draw\n" ); }
    void Update( void ){ printf( "A::Update\n" ); }
};
TRAIT_HELPER_DEF_AFTER( Draw, A );
TRAIT_HELPER_DEF_AFTER( Update, A );

TRAIT_HELPER_DEF( Draw, B );
TRAIT_HELPER_DEF( Jump, B );
class B
{
    TRAIT_USE( Draw, B );
    TRAIT_USE( Jump, B );
public:
    B() : TRAIT_INIT( Draw ), TRAIT_INIT( Jump ){}
    void Draw( void ){ printf( "B::Draw\n" ); }
    void Jump( void ){ printf( "B::Jump\n" ); }
};
TRAIT_HELPER_DEF_AFTER( Draw, B );
TRAIT_HELPER_DEF_AFTER( Jump, B );

int main( void )
{
    A a;
    B b;
    Trait_Draw* pDrawA = a.GetTrait_Draw();
    Trait_Draw* pDrawB = b.GetTrait_Draw();
    pDrawA->Draw();
    pDrawB->Draw();
    Trait_Update* pUpdate = a.GetTrait_Update();
    pUpdate->Update();
    Trait_Jump* pJump = b.GetTrait_Jump();
    pJump->Jump();
    return 0;
}
A::Draw
B::Draw
A::Update
B::Jump

利便性とかトレイトの定義とかは置いておいて、とりあえず、Draw、Updateなどの特性(トレイト)ごとの抽象化( Trait_Draw*, Trait_Update* )が継承を使わずにできてます。