読者です 読者をやめる 読者になる 読者になる

謎言語使いの徒然

適当に気になった技術や言語を流すブログ。

C言語でOOPまがい

C言語

4年ぶりにC言語を復習をしたわけだが、どうにも使いづらいw
大学の3年で少し触っただけだw
なにせそれまでずっと PHP,C++,Python なんてオブジェクト指向言語しか弄ってないからだ。

連結リスト使うかも〜と、上の人。
で予習にスタックを組む俺。

取り敢えず以下のコードを見て欲しい。
予め断っておくが Objective-C でも C++ でもなく、Cコードである。

#include <stdio.h>
#include "intstack.h"

main()
{
    int i;
    IntStack* stack = new_IntStack();
    for(i=0;i<20;i++)
    {
        stack->push(stack,i+1);
        printf("Insert to stack val : %d\n",i+1);
    }
    printf("Stack counter is : %d\n",stack->getCount(stack));
    for(i=0;i<5;i++)
    {
        printf("pop : %d\n",stack->pop(stack));
    }
    delete_IntStack(stack);
}

どう見ても C++ に汚染されたコードですw
一応残りのコードも晒しておく。

list.h

#ifndef __Node_H__
#define __Node_H__

typedef struct __node Node;
struct __node {
    void* val;
    Node* next;
};

Node* new_Node();
void* delete_Node(Node* this);

#endif

list.c

#include <stdlib.h>
#include <string.h>
#include "list.h"

Node* new_Node()
{
    Node* this = (Node*)malloc(sizeof(Node));
    if (this == NULL) return NULL;
    memset(this,0,sizeof(Node));
    return this;
}


void*  delete_Node(Node* this)
{
    void* val = this->val;
    free(this);
    return val;
}

new と delete を自前で宣言している。
スタック定義は以下。

stack.h

#ifndef __STACK_H__
#define __STACK_H__
#include "list.h"

typedef struct __stack Stack;

struct __stack {
    Node* top;
    int   count;
    void  (*push)(Stack*,void*);
    void* (*pop)(Stack*);
    int   (*getCount)(Stack*);
    void  (*clear)(Stack*);
};

/* new と delete */
Stack* new_Stack();
void   delete_Stack(Stack* this);

/* コンストラクタとデストラクタ */
void Stack_init(Stack* this);
void Stack_finish(Stack* this);

/* クラス関数 */
void  Stack_push(Stack* this,void* val);
void* Stack_pop(Stack* this);
int   Stack_count(Stack* this);
void  Stack_clear(Stack* this);

#endif

関数ポインタクラス関数を無理やり宣言してる。
正直、生粋のC言語プログラマが見たら悲鳴上げるんじゃなかろうか?
stack.c

#include <stdlib.h>
#include <string.h>
#include "stack.h"

Stack* new_Stack()
{
    Stack* this = (Stack*)malloc(sizeof(Stack));
    if(this == NULL) return NULL;
    memset(this,0,sizeof(Stack));
    /* 関数の割り当て */
    this->push = Stack_push;
    this->pop  = Stack_pop;
    this->getCount = Stack_count;
    this->clear = Stack_clear;
    /* コンストラクタのコール */
    Stack_init(this);
    return this;
}

void   delete_Stack(Stack* this)
{
    Stack_finish(this);
    free(this);
}

void Stack_init(Stack* this){}

void Stack_finish(Stack* this)
{
    Stack_clear(this);
}

void  Stack_push(Stack* this,void* val)
{
    Node* list = (Node*)malloc(sizeof(Node));
    if (list == NULL) return;
    list->val = val;
    list->next = this->top;
    this->top = list;
    this->count++;
}

void* Stack_pop(Stack* this)
{
    Node* top = this->top;
    if(top == NULL) return NULL;
    this->top = this->top->next;
    this->count--;
    return delete_Node(top);
}

int   Stack_count(Stack* this)
{
    return this->count;
}

void  Stack_clear(Stack* this)
{
    void* val;
    while ( (val = Stack_pop(this)) != NULL )
    {
        /*
         * スタックの中に積まれたデータも削除
         * そういう仕様
         */
        free(val);
    }
}

特に言うことはなさげ。
ここからがキモい(自分で見てもキモい)。

intstack.h

#ifndef __INTSTACK_H__
#define __INTSTACK_H__

#include "stack.h"

typedef struct __intstack IntStack;

/* Stack を継承 */
struct __intstack {
    Stack* super;
    void (*push)(IntStack*,int val);
    int  (*pop)(IntStack*);
    int   (*getCount)(IntStack*);
    void  (*clear)(IntStack*);
};

/* new と delete */
IntStack* new_IntStack();
void   delete_IntStack(IntStack* this);

/* コンストラクタとデストラクタ */
void IntStack_init(IntStack* this);
void IntStack_finish(IntStack* this);

/* クラス関数(全てオーバーライド) */
void  IntStack_push(IntStack* this,int val);
int   IntStack_pop(IntStack* this);
int   IntStack_count(IntStack* this);
void  IntStack_clear(IntStack* this);

#endif

継承を表現してみた。
うんキモい!
そして更にキモい実装

#include <stdlib.h>
#include <string.h>
#include "intstack.h"

/* new と delete */
IntStack* new_IntStack()
{
    IntStack* this = (IntStack*)malloc(sizeof(IntStack));
    if(this == NULL) return NULL;
    memset(this,0,sizeof(IntStack));
    /* 関数の割り当て */
    this->push = IntStack_push;
    this->pop  = IntStack_pop;
    this->getCount = IntStack_count;
    this->clear = IntStack_clear;
    /* 親クラスの生成 */
    this->super = new_Stack();
    /* コンストラクタのコール */
    IntStack_init(this);
    return this;
}

void   delete_IntStack(IntStack* this) 
{
    IntStack_finish(this);
    free(this);
}

/* コンストラクタとデストラクタ */
void IntStack_init(IntStack* this) {}
void IntStack_finish(IntStack* this)
{
    delete_Stack(this->super);
}

/* クラス関数(全てオーバーライド) */
void  IntStack_push(IntStack* this,int val)
{
    int* lpVal = (int*)malloc(sizeof(int));
    *lpVal = val;
    this->super->push(this->super,(void*)lpVal);
}

int IntStack_pop(IntStack* this)
{
    int val;
    int* lpVal = (int*)this->super->pop(this->super);
    val = *lpVal;
    free(lpVal);
    return val;
}

int   IntStack_count(IntStack* this)
{
    return this->super->getCount(this->super);
}

void  IntStack_clear(IntStack* this)
{
    this->super->clear(this->super);
}

結論。
オブジェクト指向言語でなくても、きっとそれに近いコトはできるんだよ!
(手間隙掛かるけど)
今のところ private な継承で、オーバーライド(?)かけている。