Cによる多態性の実現
先ほどの例にあげたコードを実装してみます。とあるシステムにおいて、メンバとゲストという2種類の利用者の形態が存在し、それらの形態に従って、固有の処理をしなければならない、というようなシーンの実現を考えます。また、利用者は形態に寄らずユニークなIDを持ち、メンバはそれに加えて名前情報も持つこととしましょう。
まずは利用者を表すUserクラスを定義することとします。利用者は形態に寄らずIDを持つこととしたので、生成時にIDを渡すようにしましょう。また、多態性を実現するためのメッセージとして、例でも使用したactionというメッセージを一つ用意することにします。
#ifndef _USER_H_INCLUDE_
#define _USER_H_INCLUDE_
/* Userクラスの構造定義 */
#define INTERFACE_OF_USER ¥
void* user_private_data; /* カプセル化データ */¥
int (*action)(User* self); /* 多態性を実現する規定アクション */
/* Userクラス定義 */
typedef struct _user User;
struct _user{
INTERFACE_OF_USER
};
User* User_new(int id); /* Userオブジェクト生成 */
void User_delete(User* obj); /* Userオブジェクト破棄 */
#endif
次に、 利用者の形態ごとにUserクラスを継承したサブクラスを用意します。1つ目はメンバを表現するMemberクラスです。メンバは名前情報を持つこととしたので、生成時に設定する名前情報を渡すようにします。
#ifndef _MEMBER_H_INCLUDE_
#define _MEMBER_H_INCLUDE_
#include "User.h" /* Userクラスの継承 */
/* Memberクラスの構造定義 */
#define INTERFACE_OF_MEMBER ¥
INTERFACE_OF_USER /* Userクラス構造定義の継承 */¥
void* member_private_data; /* カプセル化データ */
/* Memberクラス定義 */
typedef struct _member Member;
struct _member{
INTERFACE_OF_MEMBER
};
Member* Member_new(int id, char* name); /* Memberオブジェクト生成 */
void Member_delete(Member* obj); /* Memberオブジェクト破棄 */
#endif
2つ目はゲストを表現するGuestクラスです。こちらは、特に固有の情報を持つことにはしなかったので、Userクラスを継承しただけのシンプルなクラス定義となります。
#ifndef _GUEST_H_INCLUDE_
#define _GUEST_H_INCLUDE_
#include "User.h" /* Userクラスの継承 */
/* Guestクラスの構造定義 */
#define INTERFACE_OF_GUEST ¥
INTERFACE_OF_USER /* Userクラス構造定義の継承 */¥
void* guest_private_data; /* カプセル化データ */
/* Guestクラス定義 */
typedef struct _guest Guest;
struct _guest{
INTERFACE_OF_GUEST
};
Guest* Guest_new(int id); /* Guestオブジェクト生成 */
void Guest_delete(Guest* obj); /* Guestオブジェクト破棄 */
#endif
では、次にそれぞれのクラスの中身について実装していくことにしましょう。
まずは、Userクラスの実装です。初期化、終了の処理等を記述すると共に、actionメソッドのデフォルトの実装を行っています。
/* Userクラス属性定義 */
struct _user_attribute {
int id;
};
/* Userクラス属性アクセス用マクロ */
#define USER_ATTRIBUTE(ptr)¥
((struct _user_attribute*)(ptr->user_private_data))
/* 初期化・終了処理 */
User* User_initialize(User* self, int id);
void User_finalize(User* self);
#include "User.h"
#include "User.private.h"
#include <stdlib.h>
#include <stdio.h>
static int User_action(User* self) /* actionメソッドの実装 */
{
printf("メソッドを実装してください\n");
return 1;
}
User* User_initialize(User* self, int id) /* Userオブジェクト初期化処理 */
{
self->user_private_data = malloc(sizeof(struct _user_attribute));
USER_ATTRIBUTE(self)->id = id;
self->action = User_action;
return self;
}
void User_finalize(User* self) /* Userオブジェクト終了処理 */
{
free(USER_ATTRIBUTE(self));
}
User* User_new(int id) /* Userオブジェクト生成 */
{
User* obj = (User*)malloc(sizeof(User));
return User_initialize(obj, id);
}
void User_delete(User* obj) /* Userオブジェクト破棄 */
{
User_finalize(obj);
free(obj);
}
次に、 利用者の形態ごと用意したサブクラスの実装です。多態性を実現するために、サブクラスでそれぞれactionメソッドを実装すると共に、初期化処理においてactionメッセージにそれぞれで実装したメソッドを紐付けている所に着目してください。
#include "User.private.h" /* Userクラスカプセル化領域の継承 */
/* Memberクラス属性定義 */
struct _member_attribute {
char* name;
};
/* Memberクラス属性アクセス用マクロ */
#define MEMBER_ATTRIBUTE(ptr)¥
((struct _member_attribute*)(ptr->member_private_data))
/* 初期化・終了処理 */
Member* Member_initialize(Member* self, int id, char* name);
void Member_finalize(Member* self);
#include "Member.h"
#include "Member.private.h"
#include <stdlib.h>
#include <stdio.h>
static int Member_action(User* self) /* actionメソッドの実装 */
{
Member* obj = (Member*)self;
printf("Member :%sさん、ようこそ!¥n", MEMBER_ATTRIBUTE(obj)->name);
return 1;
}
/* Memberオブジェクト初期化処理 */
Member* Member_initialize(Member* self, int id, char* name)
{
User_initialize((User*)self, id);
self->member_private_data = malloc(sizeof(struct _member_attribute));
MEMBER_ATTRIBUTE(self)->name = name;
self->action = Member_action;
return self;
}
/* Memberオブジェクト終了処理 */
void Member_finalize(Member* self)
{
free(MEMBER_ATTRIBUTE(self)); /* 属性構造体の解放 */
User_finalize((User*)self); /* 継承領域の終了処理 */
}
/* Memberオブジェクト生成 */
Member* Member_new(int id, char* name)
{
Member* obj = (Member*)malloc(sizeof(Member));
return Member_initialize(obj, id, name);
}
/* Memberオブジェクト破棄 */
void Member_delete(Member* obj)
{
Member_finalize(obj);
free(obj);
}
#include "User.private.h" /* Userクラスカプセル化領域の継承 */
/* Guestクラス属性定義 */
struct _guest_attribute {;};
/* Guestクラス属性アクセス用マクロ */
#define GUEST_ATTRIBUTE(ptr)¥
((struct _guest_attribute*)(ptr->guest_private_data))
/* 初期化・終了処理 */
Guest* Guest_initialize(Guest* self, int id);
void Guest_finalize(Guest* self);
#include "Guest.h"
#include "Guest.private.h"
#include <stdlib.h>
#include <stdio.h>
static int Guest_action(User* self) /* actionメソッドの実装 */
{
printf("Guest : id%iさんは、実行のための権限がありません\n", USER_ATTRIBUTE((User*)self)->id);
return 1;
}
Guest* Guest_initialize(Guest* self, int id) /* Guestオブジェクト初期化処理 */
{
User_initialize((User*)self, id);
self->guest_private_data = malloc(sizeof(struct _guest_attribute));
((User*)self)->action = Guest_action;
return self;
}
void Guest_finalize(Guest* self) /* Guestオブジェクト終了処理 */
{
free(GUEST_ATTRIBUTE(self)); /* 属性構造体の解放 */
User_finalize((User*)self); /* 継承領域の終了処理 */
}
Guest* Guest_new(int id) /* Guestオブジェクト生成 */
{
Guest* obj = (Guest*)malloc(sizeof(Guest));
return Guest_initialize(obj, id);
}
void Guest_delete(Guest* obj) /* Guestオブジェクト破棄 */
{
Guest_finalize(obj);
free(obj);
}
