[Contents]
C언어와 객체지향1
C언어와 객체지향2 - 기능 추가
C언어와 객체지향3 - 확장성을 고려한 기능 추가
C언어와 객체지향4 - 상속된 기능들(기능의 상속화)
[출처] '모던 C언어 프로그래밍' - 하나이 시세이
C언어와 객체지향1
- 자료구조는 구조체로 표현하여 '객체'처럼 생성하면 편리하다.
- 매크로를 사용하여 쉽게 구조체 초기화를 한다.
Stack.h
#include <stddef.h>
typedef struct{
int top;
const size_t size;
int *const pBuf;
} Stack;
bool push(Stack *p, int val);
bool pop(Stack *p, int *pRet);
#define newStack(buf) {0, sizeof(buf) / sizeof(int), (buf)}
main.c
#include <stdbool.h>
#include "stack.h"
int main()
{
int buf[16];
Stack stack = newStack(buf);
int buf2[16];
Stack stack2 = newStack(buf2);
}
C언어와 객체지향2 - 기능 추가
- 위의 '스택'에 기능을 추가하여 보자. 구조체를 변경하기 보단 기능은 따로 분리한다.
- 예를 들어 '스택 범위 제한 기능'을 추가하여 본다.
- 이점
- 기능을 수행하는 구조체 포인터를 추가하여 기존 자료형의 변화를 최소화 한다.
Stack.h
#include <stddef.h>
typedef struct{
const int min;
const int max;
} Range;
typedef struct{
int top;
const size_t size;
int *const pBuf;
const Range *const pRange; //'범위 검사 기능'은 구조체 포인터로 구현 /* new */
} Stack; //min, max를 Stack 구조체 안에 두지 않는다.
bool push(Stack *p, int val);
bool pop(Stack *p, int *pRet);
static bool isRangeOK(const Range *p, int val); /* new */
#define newStack(buf) {0, sizeof(buf) / sizeof(int), (buf)}
#define newStackWithRangeCheck(buf, pRange) { \ /* new */
0, sizeof(buf) / sizeof(int), (buf), pRange \
}
Stack.c
static bool isRangeOK(const Range *p, int val)
return p == NULL || (p->min <= val && val <= p->max);
bool push(Stack *p, int val) {
if( !isRangeOk(p->pRange, val) || isStackFull(p) )
return false;
p->pBuf[p->top++] = val;
return true;
}
C언어와 객체지향3 - 확장성을 고려한 기능 추가
- 위의 방법은 기능이 바뀔 때 마다 Stack 구조체가 변경된다.
- 따라서, Stack 구조체 입장에서는 기능을 신경 안쓰고 싶다. Validator(기능과 데이터 포함하는) 구조체를 둔다.
- 실제 기능을 수행하는 함수에서 인자를 형변환 하여 필요에 의해 쓴다.
Stack.h
/* Abstract Struct */
typedef struct Validator {
bool (*const validate)(struct Validator *pThis, int val); //function pointer
void *const pData; //검사에 사용할 데이터, 유동적
} Validator;
typedef struct{
const int min;
const int max;
} Range;
typedef struct {
int previousValue;
} PreviousValue;
typedef struct{
int top;
const size_t size;
int *const pBuf;
Validator *const pValidator;
} Stack;
/* Stack.c */
bool validateRange(Validator *pThis, int val) {
Range *pRange = (Range *)(pThis->pData); // 기능 수행 함수에서 데이터 형변환하여 쓴다.
return pRange->min <= val && val <= pRange->max;
}
bool validatePrevious(Validator *pThis, int val){
PreviousValue *pPrevious = (PreviousValue *)pThis->pData; // 기능 수행 함수에서 데이터 형변환하여 쓴다.
if(val < pPrevious->previousValue)
return false;
pPrevious->previousValue = val;
return true;
}
#define rangeValidator(pRange) { validateRange, pRange } // 함수와 범위
#define previousValidator(pPrevious) { validatePrevious, pPrevious } // 함수와 이전 값
#define newStackWithValidator(buf, pValidator) {0, sizeof(buf) / sizeof(int), (buf), pValidator}
/*
이것 자체가 Validator 이며, 함수 포인터에 함수 주소를 넘겨주고, 데이터를 넘겨준다.
*/
main.c
Range range = {0, 9};
Validator validator = rangeValidator(&range);
Stack stack = newStackWithValidator(buf, &validator);
push(&stack, 123);
PreviousValue previoud = {0};
Validator validator = previousValidator(&previous);
Stack stack2 = newStackWithValidator(buf, &validator);
push(&stack2, 123);
C언어와 객체지향4 - 상속된 기능들(기능의 상속화)
- Validator가 기능을 수행하므로, 추가된 구조체인 Range, PreviousValue 구조체도 기능으로 만들어 버린다.
- 기존의 Validator는 부모 구조체로 만든다.
- Validator를 형 변환하여 쓴다.
- Stack을 생성할 때 &validator.base를 넣음에 주의한다. 구조체의 첫번째 멤버가 일치함으로 가능한 것.
Stack.h
/* Abstract Struct */
typedef struct Validator {
bool (*const validate)(struct Validator *pThis, int val); //function pointer
} Validator;
bool validateRange(Validator *p, int val);
bool validatePrevious(Validator *p, int val);
typedef struct{
Validator base; //(1)함수주소를 가리킨다.
const int min;
const int max;
} RangeValidator;
typedef struct {
Validator base;
int previousValue;
} PreviousValueValidator;
typedef struct{
int top;
const size_t size;
int *const pBuf;
Validator *const pValidator; //(2)함수 주소를 전달 (min, max 도 딸려온다?)
} Stack;
bool validateRange(Validator *p, int val)
{
RangeValidator *pThis = (RangeValidator *)p; // Validator 형변환
return pThis->min <= val && val <= pThis->max;
}
bool validatePrevious(Validator *p, int val)
{
PreviousValueValidator *pThis = (PreviousValueValidator*)p; // Validator 형변환
if (val < pThis->previousValue) return false;
pThis->previousValue = val;
return true;
}
#define newRangeValidator(min, max) { validateRange, min, max } // 함수와 범위
#define newPreviousValueValidator { validatePrevious, 0 } // 함수와 이전 값
#define newStackWithValidator(buf, pValidator) {0, sizeof(buf) / sizeof(int), (buf), pValidator}
main.c
RangeValidator validator = newRangeValidator(0, 9); //{ validateRange, min, max }
Stack stack = newStackWithValidator(buf, &validator.base);
반응형
'프로그래밍 언어 > Architecture' 카테고리의 다른 글
객체 지향 & 패턴 in C (2) (0) | 2021.09.27 |
---|---|
SOLID (객체 지향 설계) 설명 (0) | 2021.04.17 |