CodeZine(コードジン)

特集ページ一覧

【第4回】多態性

  • LINEで送る
  • このエントリーをはてなブックマークに追加
2008/12/22 18:15

目次

Cによる多態性の実現

 先ほどの例にあげたコードを実装してみます。とあるシステムにおいて、メンバとゲストという2種類の利用者の形態が存在し、それらの形態に従って、固有の処理をしなければならない、というようなシーンの実現を考えます。また、利用者は形態に寄らずユニークなIDを持ち、メンバはそれに加えて名前情報も持つこととしましょう。

 まずは利用者を表すUserクラスを定義することとします。利用者は形態に寄らずIDを持つこととしたので、生成時にIDを渡すようにしましょう。また、多態性を実現するためのメッセージとして、例でも使用したactionというメッセージを一つ用意することにします。

リスト3:User.h
#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クラスです。メンバは名前情報を持つこととしたので、生成時に設定する名前情報を渡すようにします。

リスト4:Member.h
#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クラスを継承しただけのシンプルなクラス定義となります。

リスト5:Guest.h
#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メソッドのデフォルトの実装を行っています。

リスト6:User.private.h
/* 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);
リスト7:User.c
#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メッセージにそれぞれで実装したメソッドを紐付けている所に着目してください。

リスト8:Member.private.h
#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);
リスト9:Member.c
#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);
}
リスト10:Guest.private.h
#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);
リスト11:Guest.c
#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);
}

  • LINEで送る
  • このエントリーをはてなブックマークに追加

バックナンバー

連載:Cでわかるオブジェクト指向

著者プロフィール

  • 島田 浩二(Ruby札幌)(シマダ コウジ)

    1978年生まれ。電気通信大学電気通信学部情報工学科卒業後、メーカ系ソフトウェア会社にて携帯電話の開発業務に従事した後、2006年より札幌にてフリーのプログラマとして活動。2009年7月に株式会社えにしテックを設立し、同社代表取締役に就任。 日本Rubyの会理事、一般社団法人LOCAL理事、Ru...

あなたにオススメ

All contents copyright © 2005-2021 Shoeisha Co., Ltd. All rights reserved. ver.1.5