オブジェクト指向の基本 - カプセル化
カプセル化とは
「カプセル化(encapsulation)」とは、オブジェクト指向の基本的な概念の1つです。カプセル化について、Wikipediaを参照すると、次のように説明されています。
オブジェクト内部のデータを隠蔽したり(データ隠蔽)、オブジェクトの振る舞いを隠蔽したり、オブジェクトの実際の型を隠蔽したりすること。
また、カプセル化を行う利点については、次のように説明されています。
外部のプログラムがデータ内部に直接アクセスを行っていた場合、このデータにアクセスしていたすべての箇所を同時に変更しなければならない。しかし公開メソッドを用いていれば、変更は内部表現から外部表現への公開メソッド内のみで済み、変更の影響を局所にとどめる事ができる。
グローバル変数の問題などに直面することの多い組込み系のプログラマであれば、上記のメリットを十分に理解してもらえるものと思います。そして、この概念を実現することが、十分なオブジェクト化を実現し、OOPの旨味を味わうための第1歩となります。

それでは、前回のコードをベースに、カプセル化の概念をCで実現していきましょう。
Cによるカプセル化の実現
まずはオブジェクトを利用する側のプログラムからオブジェクトの持つ属性を参照できないようにする必要があります。ObjectClassクラスの定義を次のように変更します。
#ifndef _OBJECTCLASS_H_INCLUDE_
#define _OBJECTCLASS_H_INCLUDE_
/* クラスの定義 */
typedef struct _object Instance;
struct _object{
void* encapsulation_data; /* 属性領域をカプセル化 */
int (*message)(Instance* self);
};
/* オブジェクト生成メソッド */
Instance* Object_new(char* name, int status);
/* オブジェクト破棄メソッド */
void Object_delete(Instance* obj);
#endif
クラス定義に存在していた属性の定義を削除し、代わりに属性用の構造体を格納する領域としてencapsulation_dataを追加しました。また、encapsulation_dataに何が格納されるか(具体的な属性用の構造体)は明らかにしていません。これにより、オブジェクトを利用する側のプログラムから属性を参照することはできなくなりました。
さて、次はオブジェクト内部から属性にアクセスできるようにしていきましょう。
まずは、ObjectClass.cの先頭で属性用の構造体および属性にアクセスするためのマクロを定義します。
/* ObjectClass属性定義 */
struct _objectclass_attribute {
char* name;
int status;
};
/* ObjectClass属性アクセス用マクロ */
#define OBJECT_CLASS_ATTRIBUTE(ptr)((struct _objectclass_attribute*)(ptr->encapsulation_data))
また、オブジェクト生成・破棄メソッドは、上記にて定義した属性構造体用のメモリ領域の確保・解放の処理を行うように変更します。
/* オブジェクト生成メソッド */
Instance* Object_new(char* name, int status)
{
Instance* obj = (Instance*)malloc(sizeof(Instance));
/* 属性構造体を生成し、属性を初期化 */
obj->encapsulation_data = malloc(sizeof(struct _objectclass_attribute));
OBJECT_CLASS_ATTRIBUTE(obj)->name = name;
OBJECT_CLASS_ATTRIBUTE(obj)->status = status;
obj->message = Object_method;
return obj;
}
/* オブジェクト破棄メソッド */
void Object_delete(Instance* obj)
{
free(OBJECT_CLASS_ATTRIBUTE(obj)); /* 属性構造体の解放 */
free(obj); /* オブジェクト自身の解放 */
}
最後に、具体的なメソッドにおける属性へのアクセス方法を以下にように変更します。
/* メソッドの実装 */
static int Object_method(Instance* self)
{
printf("%s.status = %d\n",
OBJECT_CLASS_ATTRIBUTE(self)->name,
OBJECT_CLASS_ATTRIBUTE(self)->status);
return 1;
}
