実開発に使われるC言語 [基礎から裏技まで] (5) Object-Oriented C その3 Protectedの実現
-
ここで、僕のC99でのProtectedの実装を披露いたします。考えとしては、Protected部分を別の.h/.cファイルにすることである。
// ifcs_ooc_class_a_protected.hファイル #ifndef IFCS_OOC_CLASS_A_PROTECTED_H #define IFCS_OOC_CLASS_A_PROTECTED_H #if defined (__cplusplus) extern "C" { #endif // Protected部分の構造体 typedef struct IfcsClassAProtected_tag { float f; void print_float_value(struct IfcsClassAProtected_tag* const); } IfcsClassAProtected; // Protected部分の生成 extern IfcsClassAProtected* IfcsClassAProtected_create(); // Protected部分の消滅 extern void IfcsClassAProtected_destroy( IfcsClassAProtected* const self); #if defined (__cplusplus) } #endif #endif /* IFCS_OOC_CLASS_A_PROTECTED_H */
------------- 分割線 ----------------
// ifcs_ooc_class_a_protected.cファイル #include <stdio.h> #include "ifcs_ooc_class_a_protected.h" // 関数の実装 static void print(IfcsClassAProtected* const self) { printf("Print From Protected, value=%f\n", self->f); } // 外部関数の実装 IfcsClassAProtected* IfcsClassAProtected_create() { IfcsClassAProtected* p_protected = NULL; if (NULL == (p_protected = (IfcsClassAProtected*)malloc(sizeof(IfcsClassAProtected)))) { return NULL; } p_protected->print_float_value = print; } void IfcsClassAProtected_destroy( IfcsClassAProtected* const self) { memset(self, 0x00, sizeof(IfcsClassAProtected)); free(self); }
以上はProtected部分の実装の例。続いては、Protected部分をClassに取り入れる。下の void *p_protected部分を注目しましょう。
// ifcs_ooc_class_a.h ClassAの定義、void *p_privateでprivateの部分を隠す typedef struct IfcsClassA_tag { // public: int input_val; void printVal(struct IfcsClassA_tag* const); /* Protected部分の機能をInvokeする */ void printFloatVal(struct IfcsClassA_tag* const); // private: void *p_private; /* protected: */ void *p_protected; } IfcsClassA;
------------- 分割線 ----------------
// ifcs_ooc_class_a.c の実装、なかでprivateの部分を定義する #include "ifcs_ooc_class_a.h" /* Protected部分を別のファイルにして、.cファイルからincludeする */ #include "ifcs_ooc_class_a_protected.h" // <1>. Privateの内容を1つのStruct構造体で格納して、実装を書く typedef struct IfcsClassAPrivate_tag { int count; void calc_value(struct IfcsClassAPrivate_tag* const, int const); } IfcsClassAPrivate; static int calc_value(IfcsClassAPrivate* const p_private, int const origin) { if (NULL != p_private) { int result = p_private->count + origin; p_private->count++; return result; } else { return origin; } } static IfcsClassAPrivate* IfcsClassAPrivate_create() { IfcsClassAPrivate *p_private = NULL; p_private = (IfcsClassAPrivate*)malloc(sizeof(IfcsClassAPrivate)); p_private->calc_value = calc_value; p_private->count = 0; ... return p_private; ... } ... // Privateの部分はここまで // ここからは、ClassAのpublicの部分の内容です。 static void printVal(IfcsClassA * const self); static void printFloatVal(IfcsClassA * const self); IfcsClassA* IfcsClassA_create() { /* Protected部分のPointer */ IfcsClassAProtected* p_protected = NULL; ... p_obj_a->p_private = IfcsClassAPrivate_create(); ... p_obj_a->printVal = printVal; ... /* Protected部分の生成 */ p_protected = IfcsClassAProtected_create(); p_protected->f = 0.1; p_obj_a->p_protected = p_protected; p_obj_a->printFloatVal = printFloatVal; } void IfcsClassA_destroy( IfcsClassA ** const self) { /* Protected部分のPointer */ IfcsClassAProtected* p_protected = ()p_obj_a->p_protected; ... IfcsClassAPrivate_destroy(&p_obj_a->p_private); ... /* Protected部分の消滅 */ IfcsClassAProtected_destroy(p_obj_a->p_protected); p_obj_a->p_protected = NULL; } static void IfcsClassA_initialize(IfcsClassA * const self) { ... self->input_val = 0; ... } static void printVal( IfcsClassA * const self) { IfcsClassAPrivate *p_private = NULL; int result = -1; if (NULL != self) { result = self->input_val; if (NULL != self->p_private) { // Cのポインター変換で、private領域を内部でアクセスする p_private = (IfcsClassAPrivate*)self->p_private; result = p_private->calc_value(p_private, result); } } printf("class a value is %d\n", result); } /* Protected関数をInvokeする */ static void printFloatVal( IfcsClassA * const self) { IfcsClassAProtected *p_protected = NULL; assert((NULL != self) && (NULL != self->p_protected)); p_protected = (IfcsClassAProtected*)self->p_protected; p_protected->print_float_value(p_protected); }
これでProtected部分をClassに取り入れました。次にそれを使ってみよう。
int main(int argc, char *argv[]) { int i = 0; IfcsClassA *p_obj_a = IfcsClassA_create(); p_obj_a->input_val = 1; for (; i < 10; ++i) { p_obj_a->printVal(p_obj_a); } /* Protected部分を使う */ p_obj_a->printFloatVal(p_obj_a); p_obj_a->finalize(p_obj_a); IfcsClassA_destroy(&p_obj_a); }
以上です。
まとめ:C言語のポインタの変換機能をうまく利用して、クラス内にPrivate部分と同じくvoid*のポインタを用意する。次に、Private部分を直接にクラスの.cの内部に書くのと違って、別のファイルとしてProtected部分を書き出すこと。すると、クラスを通してProtected部分を直接にアクセスできないが、また別のクラスを作る場合、Protected部分をファイルのIncludeで流用することができる。