i-focus i-focus BB
    • カテゴリ
    • 最近
    • タグ
    • 人気
    • ユーザー
    • グループ
    • 登録
    • ログイン

    実開発に使われるC言語 [基礎から裏技まで] (3) Object-Oriented C その1 継承

    C言語
    1
    1
    224
    もっと見る
    • 古いものから新しい順
    • 新しいものから古い順
    • 最高評価
    返信
    • スレッドとして返信する
    投稿するのにログインして下さい
    このスレッドが削除されました。スレッド管理権を持っているユーザーにしか読めません。
    • Z
      zhengyu.chen
      最後に編集した時間zhengyu.chen

      CでもObject-Orientの手法でプログラミングすることができる。実作業の中でもこういった手法を多用されています。実際、CでObject-Orientationのプログラミングの実装方法はいくつがありますが、完全網羅することができませんが、個人の知っているいくつかの実装方法をこれから何Threadをかけて説明したいと思います。

      <1>. struct と ポインター変換の力を利用する
      まずは基底クラスを定義しましょう。

      // file ifcs_ooc_base_class.h: 基底クラスの定義
      
      #ifndef IFCS_OOC_BASE_CLASS_H
      #define IFCS_OOC_BASE_CLASS_H
      
      #if defined (__cplusplus)
      extern "C" {
      #endif
      
      typedef struct IfcsBaseClass_tag {
          int base;
      } IfcsBaseClass;
      
      #if defined (__cplusplus)
      }
      #endif
      
      #endif  /* IFCS_OOC_BASE_CLASS_H */
      

      続いて、継承関係のサブクラスA, Bを定義しよう。

      // ifcs_ooc_class_a.h
      #ifndef IFCS_OOC_CLASS_A_H
      #define IFCS_OOC_CLASS_A_H
      
      #include "ifcs_ooc_base_class.h"
      
      #if defined (__cplusplus)
      extern "C" {
      #endif
      
      typedef struct IfcsClassA_tag {
          IfcsBaseClass   *p_parent;
          int             a;
      } IfcsClassA;
      
      #if defined (__cplusplus)
      }
      #endif
      
      #endif  /* IFCS_OOC_CLASS_A_H */
      
      // ifcs_ooc_class_b.h
      #ifndef IFCS_OOC_CLASS_B_H
      #define IFCS_OOC_CLASS_B_H
      
      #include "ifcs_ooc_base_class.h"
      
      #if defined (__cplusplus)
      extern "C" {
      #endif
      
      typedef struct IfcsClassB_tag {
          IfcsBaseClass   *p_parent;
          float           b;
      } IfcsClassB;
      
      #if defined (__cplusplus)
      }
      #endif
      
      #endif  /* IFCS_OOC_CLASS_B_H */
      

      以上で、基底クラスと、その2つのサブクラスの定義は完了した。
      で、これらをどう使うべきか?ここで、C言語の武器であるポインターの登場になります。

      使い方を見る前に、まず、クラスにメソッド(method)を追加しましょう。

      // file ifcs_ooc_base_class.h: 基底クラスの定義
      
      #ifndef IFCS_OOC_BASE_CLASS_H
      #define IFCS_OOC_BASE_CLASS_H
      
      #if defined (__cplusplus)
      extern "C" {
      #endif
      
      typedef struct IfcsBaseClass_tag {
          int base;
      
          void (*initialize)(struct IfcsBaseClass_tag* const self);
          void (*finalize)(struct IfcsBaseClass_tag* const self);
          void (*setVal)(struct IfcsBaseClass_tag* const self, int val);
          int (*getVal)(struct IfcsBaseClass_tag* const self);
      } IfcsBaseClass;
      
      
      extern
      IfcsBaseClass*
      IfcsBaseClass_create();
      
      
      extern
      void
      IfcsBaseClass_destroy(
          IfcsBaseClass ** const self);
      
      
      #if defined (__cplusplus)
      }
      #endif
      
      #endif  /* IFCS_OOC_BASE_CLASS_H */
      
      // ifcs_ooc_base_class.c 基底クラスの実装
      #include <string.h>
      #include "ifcs_ooc_base_class.h"
      
      /** static function declaration*/
      static void IfcsBaseClass_initialize(IfcsBaseClass* const self);
      static void IfcsBaseClass_finalize(IfcsBaseClass* const self);
      static void IfcsBaseClass_setVal(IfcsBaseClass* const self, int val);
      static int IfcsBaseClass_getVal(IfcsBaseClass* const self);
      
      IfcsBaseClass*
      IfcsBaseClass_create() {
          IfcsBaseClass *p_obj_base = NULL;
      
          if (NULL != (p_obj_base = (IfcsBaseClass*)malloc(sizeof(IfcsBaseClass)) )) {
              p_obj_base->initialize = IfcsBaseClass_initialize;
              p_obj_base->finalize   = IfcsBaseClass_finalize;
              p_obj_base->setVal     = IfcsBaseClass_setVal;
              p_obj_base->getVal     = IfcsBaseClass_getVal;
          }
          
          return p_obj_base;
      }
      
      void
      IfcsBaseClass_destroy(
          IfcsBaseClass ** const self)
      {
          if ((NULL != self) && (NULL != (*self))) {
              (*self)->finalize(*self);
              free(*self);
              *self = NULL;
          }
      }
      
      /** static function definitions */
      static void IfcsBaseClass_initialize(IfcsBaseClass* const self)
      {
          if (NULL != self) {
              self->base = -1;
          }
      }
      static void IfcsBaseClass_finalize(IfcsBaseClass* const self)
      {
          if (NULL != self) {
              memset(self, 0x00, sizeof(IfcsBaseClass));
          }
      }
      static void IfcsBaseClass_setVal(IfcsBaseClass* const self, int val)
      {
          if (NULL != self) {
              self->base = val;
          }
      }
      static int IfcsBaseClass_getVal(IfcsBaseClass* const self)
      {
          if (NULL != self) {
              return self->base;
          }
          return -1;
      }
      

      続いて、ClassAとClassBに対してもメソッドを追加する。

      // ifcs_ooc_class_a.h , クラスAの定義、defineマクロやincludeなどを省略した
      typedef struct IfcsClassA_tag {
          IfcsBaseClass *p_parent;
          int a;
      
          void (*initialize)(struct IfcsClassA_tag* const self);
          void (*finalize)(struct IfcsClassA_tag* const self);
          void (*setVal)(struct IfcsClassA_tag* const self, int val);
          int (*getVal)(struct IfcsClassA_tag* const self);
      } IfcsClassA;
      
      extern
      IfcsClassA*
      IfcsClassA_create();
      
      
      extern
      void
      IfcsClassA_destroy(
          IfcsClassA** const self);
      
      // ifcs_ooc_class_a.c // クラスAの実装
      #include <string.h>
      #include "ifcs_ooc_class_a.h"
      
      /** static function declaration*/
      static void IfcsClassA_initialize(IfcsClassA * const self);
      static void IfcsClassA_finalize(IfcsClassA * const self);
      static void IfcsClassA_setVal(IfcsClassA * const self, int val);
      static int IfcsClassA_getVal(IfcsClassA * const self);
      
      IfcsClassA*
      IfcsClassA_create() {
          IfcsClassA *p_obj_a= NULL;
      
          if (NULL != (p_obj_a= (IfcsClassA*)malloc(sizeof(IfcsClassA)) )) {
              if (NULL != (p_obj_a->p_parent = IfcsBaseClass_create())) {
                  p_obj_a->initialize = IfcsClassA_initialize;
                  p_obj_a->finalize   = IfcsClassA_finalize;
                  p_obj_a->setVal     = IfcsClassA_setVal;
                  p_obj_a->getVal     = IfcsClassA_getVal;
              } else {
                  goto L_destroy;
              }
          }
          return p_obj_base;
      
      L_destroy:        
          if (NULL != p_obj_a) {    
              free(p_obj_a);
              p_obj_a = NULL;
              return p_obj_a;
          }
      }
      
      void
      IfcsClassA_destroy(
          IfcsClassA** const self)
      {
          if ((NULL != self) && (NULL != (*self))) {
              if (NULL != self->p_parent) { IfcsBaseClass_destroy(&self->p_parent); }
              (*self)->finalize(*self);
              free(*self);
              *self = NULL;
          }
      }
      
      /** static function definitions */
      static void IfcsClassA_initialize(IfcsClassA* const self)
      {
          if (NULL != self) {
              if (NULL != self->p_parent) { IfcsBaseClass_initialize(self->p_parent); }
              self->a = -2;
          }
      }
      static void IfcsClassA_finalize(IfcsClassA* const self)
      {
          if (NULL != self) {
              if (NULL != self->p_parent) { IfcsBaseClass_finalize(self->p_parent); }
              memset(self, 0x00, sizeof(IfcsClassA));
          }
      }
      static void IfcsClassA_setVal(IfcsClassA* const self, int val)
      {
          if (NULL != self) {
              self->a = val;
          }
      }
      static int IfcsClassA_getVal(IfcsClassA* const self)
      {
          if (NULL != self) {
              return self->a;
          }
          return -2;
      }
      

      また、ClassBに対しても同じように実装するが、ここで省略していきます。
      これですべてを整えた。では、下記のmain関数を見てみましょう。

      #include <stdio.h>
      #include "ifcs_ooc_class_a.h"
      #include "ifcs_ooc_class_b.h"
      int main(int argc, char* argv[]) {
          IfcsClassA *p_obj_a = IfcsClassA_create();
          IfcsClassB *p_obj_b = IfcsClassB_create();
      
          // 各自のクラスのinitializeを行う
          p_obj_a->initialize(p_obj_a);
          p_obj_b->initialize(p_obj_b);
      
          // 基底クラスのメソッドを使う
          p_obj_a->p_parent->setVal(p_obj_a->p_parent, 100);
          p_obj_b->p_parent->setVal(p_obj_b->p_parent, 1000);
          printf("class a base value = %d\n", p_obj_a->p_parent->getVal(p_obj_a->p_parent));
          printf("class b base value = %d\n", p_obj_b->p_parent->getVal(p_obj_b->p_parent));
      
          // 各自クラスのメソッドを使う
          p_obj_a->setVal(p_obj_a, 50);
          p_obj_b->setVal(p_obj_b, 100.0f);
          printf("class a value = %d\n", p_obj_a->getVal(p_obj_a));
          printf("class b value = %f\n", p_obj_b->getVal(p_obj_b));
      
          // 各自クラスのfinalizeを行う
          p_obj_a->finalize(p_obj_a);
          p_obj_b->finalize(p_obj_b);
      
          IfcsClassA_destroy(&p_obj_a);
          IfcsClassB_destroy(&p_obj_b);
      }
      

      これで一応簡単なObject-Orientationの実装ができました。もちろんprotectとか、privateなどのアクセス制限はどうするかとか、基底クラスをもう少し簡単にアクセスできるようにとか、いろいろと問題点があると思いますが、これからはこれをベースにどんどん説明して進化させていきたいと思います。今回は以上になります。少しでもお役に立つと幸いです。

      1 件の返信 最後の返信 返信 引用 0
      • First post
        Last post