불투명 구조체 정의하기
Coddy C 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 61개 중 18번째.
이제 opaque pointer의 개념을 이해했으니, 이 pattern을 완성하는 방법을 살펴보겠습니다. 헤더는 타입이 존재한다고 선언하지만, 실제로 그 안에 무엇이 들어 있는지 define하는 곳은 소스 파일입니다.
전체 설정은 다음과 같습니다. 먼저 정방향 선언만 포함된 헤더입니다:
// counter.h
#ifndef COUNTER_H
#define COUNTER_H
typedef struct Counter Counter; // 불완전 타입
Counter *create_counter(int start);
void free_counter(Counter *c);
#endif
그런 다음 소스 파일에는 actual struct definition이 포함됩니다:
// counter.c
#include "counter.h"
#include <stdlib.h>
struct Counter {
int value; // 외부에서 숨겨져 있음!
int step;
};
Counter *create_counter(int start) {
Counter *c = malloc(sizeof(Counter));
c->value = start;
c->step = 1;
return c;
}
void free_counter(Counter *c) {
free(c);
}
핵심 내용: struct Counter { ... }는 .c 파일에만 나타납니다. counter.h를 include하는 모든 파일은 Counter가 존재한다는 것을 알지만 value 또는 step을 볼 수는 없습니다. main.c에서 c->value를 작성하려고 하면 컴파일러 오류가 발생합니다. members는 실제로 보이지 않습니다.
이러한 분리는 C에서 캡슐화의 토대입니다. 다음 단계는 getter 및 setter 함수를 통해 제어된 접근을 제공하는 것입니다.
챌린지
쉬움Timer 모듈을 만들어 opaque pointer pattern을 시연해 봅시다. 소스 파일 내부에 구조체 정의를 숨겨 모듈을 사용하는 어떤 코드에서도 내부 members가 완전히 보이지 않도록 연습합니다.
세 개의 파일을 만들게 됩니다.
timer.h: 이것은 public interface입니다. forward declaration만 사용하여 opaqueTimer타입을 Declare합니다. 여기에는 struct body를 작성하지 않습니다! 또한 두 함수를 Declare합니다.create_timer는 seconds를 위한 integer를 받아 Timer pointer를 returns하고,free_timer는 Timer pointer를 받아 정리합니다.TIMER_Hsymbol을 사용하여 include guards를 작성합니다.timer.c: secret이 있는 곳입니다. 두 개의 Hidden members인int seconds와int running을 포함하는 actualstruct Timer를 Define합니다. (running에는 running 상태일 때 1, stopped 상태일 때 0을 사용합니다.) struct를 Allocate하고,seconds를 provided value로 Initialize하며,running을 1로 설정하도록 constructor를 Implement합니다. memory를 Free하도록 destructor를 Implement합니다.main.c: Timer 모듈을 사용하여 timer를 만들고 성공적으로 created되었는지 확인합니다. struct members가 Hidden되어 있으므로 직접 access할 수 없습니다. 이것이 핵심입니다! creation을 확인하는 message를 Print한 다음 timer를 Free하고 cleanup message를 Print합니다.
timer를 Initialize할 number of seconds(integer) 하나를 input으로 받습니다.
main file에서 provided seconds value로 timer를 만듭니다. creation message를 Print한 다음 timer를 Free하고 confirmation을 Print합니다.
다음 형식으로 output을 Print합니다.
Timer created
Timer freed여기서 핵심 insight는 main.c가 Timer pointers로 작업할 수 있지만 seconds 또는 running에 직접 access할 방법은 없다는 것입니다. main.c에서 t->seconds를 작성하려고 하면 compiler error가 발생합니다. struct body는 timer.c에서만 Define되어 있기 때문입니다. 이것이 진정한 encapsulation입니다. implementation details가 모듈 사용자에게 완전히 Hidden됩니다.
직접 해보기
#include <stdio.h>
#include "timer.h"
int main() {
int seconds;
scanf("%d", &seconds);
// TODO: 제공된 seconds 값으로 타이머를 생성하세요
// TODO: Print "Timer created"
// TODO: 타이머를 해제하세요
// TODO: "Timer freed"를 출력하세요
return 0;
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
직접 연습해 보세요: 온라인 C 컴파일러