Posted at

C言語でクラス表現


やろうとしていること。


  • C言語でクラスを表現したい。


背景


  • C言語のコンパイラしかない組み込み系などでは、UMLでクラス図書いても何かむなしい。

  • よってC言語でもクラスっぽい表現で記述したい。


方針


  • クラスはstructで表現。

  • メンバはstructのメンバそのもの。

  • 継承を実現するため、メソッドは関数ポインタをstructのメンバにして、初期化時にメソッド実体のポインタを渡す。

  • クラス(struct)の初期化はマクロを用意する。

  • メソッドの呼び出しも親側で呼び出しマクロを用意する。初期化時に与えられた関数ポインタにより、親子どちらかの適切な方のメソッド実体が呼び出される。

  • privateメンバ、メソッドは.cファイル側にstaticにして記述し隠す。

  • protectedはあきらめてpublicにする(ヘッダに書く)。


コード(ヘッダのみ)


親クラス


Controller.h

#ifndef _CONTROLLER_H_INCLUDED_

#define _CONTROLLER_H_INCLUDED_

#include "Common.h"

// クラス定義
struct Controller {
// メンバ: _で名称開始
int _data;

// メソッド
// 関数ポインタで表現
void ( *Initialize )( struct Controller* const self );
void ( *Execute )( struct Controller* const self );
};

/// コンストラクタ
extern void Controller_Constructor(
struct Controller* const self,
int data );

// メソッド実体定義
extern void Controller_Initialize( struct Controller* const self );
extern void Controller_Execute( struct Controller* const self );

/// メンバー初期化定義
#define Controller_InitMembers \
._data = 0,

/// メソッド初期化定義
#define Controller_InitMethods \
.Initialize = Controller_Initialize, \
.Execute = Controller_Execute, \

/// 初期化定義
#define Controller_Init \
{ \
Controller_InitMembers \
Controller_InitMethods \
}

// 仮想メソッドの呼び出し
#define Controller_initialize( self ) V_METHOD( self, Controller, Initialize )
#define Controller_execute( self ) V_METHOD( self, Controller, Execute)

#define _Controller( self ) ( (struct Controller*)self )
#endif



共通ヘッダ

共通ヘッダでの仮想メソッド呼び出しマクロを定義


Common.h

// Virtual Method General

#define V_METHOD( self, Type, Method ) ( (struct Type*)( self ) )->Method( (struct Type*)( self ) )
#define V_METHOD_ARG1( self, Type, Method, arg1 ) ( (struct Type*)( self ) )->Method( (struct Type*)( self ), arg1 )
#define V_METHOD_ARG2( self, Type, Method, arg1, arg2 ) ( (struct Type*)( self ) )->Method( (struct Type*)( self ), arg1, arg2 )


継承クラス(子クラス)


PanelController.h

#ifndef _PANEL_CONTROLLER_H_INCLUDED_

#define _PANEL_CONTROLLER_H_INCLUDED_

#include "Controller.h"

// 子クラス定義
struct PanelController {
// 親クラスを実体として持つ
struct Controller __baseClass;

// 子クラスのメンバ
int _height;

// 子クラスのメソッド
int ( *GetHeight )( struct PanelController* const self );
};

// メンバ定義
extern void PanelController_Initialize( struct Controller* const self );
extern void PanelController_Execute( struct Controller* const self );
extern int PanelController_GetHeight( struct Controller* const self );

/// コンストラクタ
extern void PanelController_Constructor(
struct PanelController* const self,
int data,
int height );

/// 親クラス初期化定義
#define PanelController_InitParent \
{ \
Controller_InitMembers \
.Initialize = PanelController_Initialize, \
.Execute = PanelController_Execute, \
},

/// メンバー初期化定義
#define PanelController_InitMembers \
._height = 0,

/// メソッド初期化定義
#define PanelController_InitMethods \
.GetHeight = PanelController_GetHeight,

/// 初期化定義
#define PanelController_Init \
{ \
PanelController_InitParent \
PanelController_InitMembers \
PanelController_InitMethods \
}

#define _PanelController( self ) ( (struct PanelController*)self )
#endif



使用例


main.c

// 実体化

struct PanelController controller = PanelController_Init;

// コンストラクタ
PanelController_Constructor( &controller, 100, 200 );

// メソッド呼び出し
Controller_initialize( &controller );
Controller_execute( &controller );



参考