Object Oriented Programming(OOP) in c - example
OOP
OOP란 객체 지향으로 프로그래밍을 하는것을 말합니다.일반적으로 C는 절차지향언어로 알고있는데, C도 구조를 잘 잡으면 객체지향으로 프로그래밍을 할 수 있습니다.
예제.
git clone
https://github.com/juwith/oop-animal.git
git checkout
aa07ba3a4e6956ca18065e4b434791b5ae622e45
|
구조
annimal이라는 객체를 생성합니다. 가장 base object입니다.
그리고 annimal 밑에는 amphibia, mammal등과 같이 annimal을 나눌 수 있는 객체들이 있습니다. 이 객체(amphibia, amammal...) 밑에는 실제 동물의 객체들이 있습니다.
animal의 객체는 모든 하위 객체가 할 수 있는 동작(method), 데이터(private)를 정의할 수 있습니다.
amphibia,mammal... 객체에는 animal을 상속받아 추가로 필요한 동작이나 데이터를 정의할 수 있습니다. (...을 붙인 이유는 확장이 가능하기 때문입니다.)
cat,dog는 mammal 객체를 상속받았는데, mammal은 animal을 상속받았기 때문에 아래와 같은 동작이 가능합니다.
- animal의 method,data를 사용 가능함.
- mammal의 method,data를 사용 가능함
prog는 amphibia를 상속받았기 때문에 mammal의 method와 data는 사용하지 못하며 아래와 같은 동작이 가능합니다.
- animal의 method,data를 사용 가능함.
- amphbia의 method,data를 사용 가능함
소스트리
샘플 소스의 트리를 보는 방법은 아래와 같습니다.
src : 객체 lib
- base : base object
- amphbia, mammal : base object를 상속받은 object
tests : 객체 lib를 이용한 샘플 코드
소스
base object
C에서 OOP를 위해서는 헤더 정의하는 부분이 중요합니다.
header에 구조체가 class형식으로 정의가 가능합니다.
typedef struct ANI_Obj ANI_Obj; struct ANI_Obj { //private data char* name; bool alive; //virtual func struct ANI_Vfunc *vfunc; //public function void (*action)(struct ANI_Obj* obj); void (*set_alive)(struct ANI_Obj* obj, bool alive); bool (*isalive)(struct ANI_Obj* obj); void (*destroy)(struct ANI_Obj* obj); }; //virtual function struct ANI_Vfunc { void (*set_name)(ANI_Obj* obj,char* name); char* (*get_name)(ANI_Obj* obj); void (*print_info)(ANI_Obj* obj); };
- private data 변수 또는 구조체를 정의합니다.
- virtual func은 필요에 따라 구성합니다.
*virtual func을 만드는 이유는 상속받은 클래스가 virtual func를 강제로 구현하게 하는 일종의 interface 역할입니다. - 상속받은 object가 사용할 수 있는 public 함수를 만듭니다.
그리고 함수를 사용하기 위해서는 'obj->action'과 같이 상속받은 객체에서 직접 호출을 할 수 있지만, 일반적인 C의 OOP는 2가지 방식으로 함수를 호출합니다.
- 매크로 정의
- inline 정의
#define Animal_Func(obj, data) ((( struct Animal *)(obj))->funcTable->moveTo((obj),(data)))
static inline void ANI_set_name(ANI_Obj *obj,char* name) { obj->vfunc->set_name(obj,name); }
상속 object
mammal
base object를 상속받아 Mammal 객체를 생성할 수 있습니다.
#include "base_object.h" typedef struct Mammal_Obj Mammal_Obj; struct Mammal_Obj { ANI_Obj* super; //add private data //struct Mammal_Vfunc *vfunc; // add later void (*action_mam)(Mammal_Obj* obj); void (*destroy)(Mammal_Obj* obj); };
구조체 내에 base object의 구조체를 정의하게 되면 base object를 상속받게됩니다.
base object구조체는 내부에 데이터, 함수포인터 등이 있기때문에 상속이 가능한것입니다.
base object구조체는 내부에 데이터, 함수포인터 등이 있기때문에 상속이 가능한것입니다.
dog
mammal object를 상속받아 dog 객체를 생성할 수 있습니다.#include "base_mammal.h" typedef struct Dog Dog; struct Dog { Mammal_Obj* super; void (*action_dog)(Dog* obj); void (*destroy)(Dog* obj); };
결과
#include <stdio.h> #include <stdbool.h> #include "dog.h" #include "cat.h" #include "prog.h" int main() { Dog* dog = Dog_init(); Dog_action(dog); char* name = "puppy"; Dog_set_name(dog,name); char* getname = Dog_get_name(dog); printf("getname is : %s \n",getname); Dog_set_alive(dog,true); Dog_print_info(dog); Cat* cat = Cat_init(); Cat_action(cat); Prog* prog = Prog_init(); Prog_action(prog); Dog_destroy(dog); Cat_destroy(cat); Prog_destroy(prog); return 0; }
상속받은 객체를 생성하여 각 객체별 동작하는 샘플코드입니다.
결과
-bash-4.2$ ./test/animal_action base action from animal class add action from mammal class add action from dog class set name : puppy getname is : puppy print name is : puppy, alive 1 base action from animal class add action from mammal class add action from cat class base action from animal class add action from amphibia class add action from Prog class
'base action from animal class' 로그는 최상위 object인 animal object에 정의되어 있는 동작입니다.
'add action from mammal class' 로그는 animal object를 상속받아 mammal object에서 정의되어있는 동작입니다.
'add action from dog class' 로그는 mammal object를 상속받아 dog에서 정의되어있는 동작입니다.
다른 객체(cat 등..)을 생성하더라도 animal, mammal에 있는 동작을 상속받을 수 있습니다.

댓글
댓글 쓰기