LoginSignup
4
8

More than 3 years have passed since last update.

C言語でクラス表現

Last updated at Posted at 2019-07-11

やろうとしていること。

  • 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 );

参考

4
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
8