객체 지향 프로그래밍(OOP)은 실제 세계의 개체들을 모델링하고 해당 개체들 간의 상호 작용을 표현하는 소프트웨어 개발 방법론입니다. C 언어는 기본적으로 절차 지향적이지만, OOP의 개념을 일부 활용할 수 있습니다. 이번에는 C 언어로 객체 지향 프로그래밍을 구현하는 방법과 응용에 대해 알아보겠습니다.
객체 지향 프로그래밍의 핵심 원칙
객체 지향 프로그래밍은 캡슐화, 상속, 다형성 등의 핵심 원칙을 포함하고 있습니다. C 언어에서 이러한 개념들을 활용하기 위해서는 몇 가지 기술과 패턴이 필요합니다.
구조체와 함수 포인터
구조체를 사용하여 데이터와 관련 함수를 묶는 것은 객체 지향 프로그래밍의 캡슐화를 모방할 수 있는 방법 중 하나입니다. 함수 포인터를 구조체 멤버로 사용하여 해당 함수에 대한 참조를 저장할 수 있습니다. 이를 통해 다형성과 비슷한 효과를 낼 수 있습니다.
typedef struct {
int (*calculateArea)(int, int);
} Shape;
int calculateRectangleArea(int width, int height) {
return width * height;
}
int main() {
Shape rectangle;
rectangle.calculateArea = calculateRectangleArea;
}
포인터와 동적 할당
동적 할당을 통해 객체를 생성하고 이에 대한 포인터를 사용하여 객체를 다룰 수 있습니다. 이를 통해 객체의 생명 주기를 관리하고 메모리를 효율적으로 활용할 수 있습니다.
typedef struct {
int width;
int height;
} Rectangle;
Rectangle* createRectangle(int width, int height) {
Rectangle* rect = (Rectangle*)malloc(sizeof(Rectangle));
rect->width = width;
rect->height = height;
return rect;
}
void destroyRectangle(Rectangle* rect) {
free(rect);
}
int main() {
Rectangle* myRect = createRectangle(5, 10);
destroyRectangle(myRect);
}
함수 포인터와 콜백
함수 포인터를 콜백 메커니즘으로 사용하여 다른 객체에 의해 호출되어야 하는 함수를 지정하는 것도 가능합니다. 이를 통해 상속과 유사한 효과를 얻을 수 있습니다.
typedef struct {
void (*onClicked)();
} Button;
void defaultOnClick() {
printf("Button clicked\n");
}
int main() {
Button myButton;
myButton.onClicked = defaultOnClick;
myButton.onClicked();
}
이처럼 C 언어를 이용하여 객체 지향 프로그래밍을 구현할 수 있지만, C++나 Java 등의 언어에 비해 직접적으로 지원하는 기능이 제한적이기 때문에 OOP를 엄격하게 따르는 것은 어렵습니다. 하지만 OOP의 기본적인 개념과 원리를 이해하고 적절히 활용한다면 C 언어로도 객체 지향적인 코드를 작성할 수 있습니다.
참고 자료
- “Object-Oriented Programming in C” by Axel Schreiner
- “Object-Oriented Programming and Structures in C” by Br. David Carlson