やろうとしていること。
- C言語でクラスを表現したい。
背景
- C言語のコンパイラしかない組み込み系などでは、UMLでクラス図書いても何かむなしい。
- よってC言語でもクラスっぽい表現で記述したい。
方針
- クラスはstructで表現。
- メンバはstructのメンバそのもの。
- 継承を実現するため、メソッドは関数ポインタをstructのメンバにして、初期化時にメソッド実体のポインタを渡す。
- クラス(struct)の初期化はマクロを用意する。
- メソッドの呼び出しも親側で呼び出しマクロを用意する。初期化時に与えられた関数ポインタにより、親子どちらかの適切な方のメソッド実体が呼び出される。
- privateメンバ、メソッドは.cファイル側にstaticにして記述し隠す。
- protectedはあきらめてpublicにする(ヘッダに書く)。
コード(ヘッダのみ)
親クラス
#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
共通ヘッダ
共通ヘッダでの仮想メソッド呼び出しマクロを定義
// 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 )
継承クラス(子クラス)
#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
使用例
// 実体化 struct PanelController controller = PanelController_Init; // コンストラクタ PanelController_Constructor( &controller, 100, 200 ); // メソッド呼び出し Controller_initialize( &controller ); Controller_execute( &controller );
参考
- C言語でオブジェクト指向を表現する (クラス、継承) – Qiita
- コンストラクタ
- メソッド継承はなし
- C 言語によるオブジェクト記述法 COOL
- メソッドの継承も含む
- ちょっと複雑
- SMC: The State Machine Compiler
- StateMachineのコード生成にはSMCを使うので、SMCの吐き出すC言語コードも参考にする。
Qiitaにも同様の記事を載せています。
C言語でクラス表現 - Qiita
やろうとしていること。C言語でクラスを表現したい。背景C言語のコンパイラしかない組み込み系などでは、UMLでクラス図書いても何かむなしい。よってC言語でもクラスっぽい表現で記述したい。方針クラスはstructで表現…
コメント