불투명 구조체 정의하기
Coddy C 여정의 Object Oriented Programming 섹션에 포함된 레슨 — 61개 중 18번째.
이제 불투명 포인터(opaque pointers)의 개념을 이해했으므로, 패턴을 완성하는 방법을 살펴보겠습니다. 헤더는 타입이 존재함을 선언하지만, 실제 내부 내용은 소스 파일에서 정의합니다.
전체 설정은 다음과 같습니다. 먼저, 전방 선언(forward declaration)만 포함된 헤더입니다:
// counter.h
#ifndef COUNTER_H
#define COUNTER_H
typedef struct Counter Counter; // 불완전한 타입
Counter *create_counter(int start);
void free_counter(Counter *c);
#endif
그 다음, 소스 파일에는 실제 구조체 정의가 포함됩니다:
// 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를 포함하는 모든 파일은 Counter가 존재한다는 것은 알지만 value나 step을 볼 수는 없습니다. main.c에서 c->value를 작성하려고 시도하면 컴파일러 오류가 발생합니다. 즉, 멤버들이 실제로 보이지 않게 됩니다.
이러한 분리는 C 언어에서 캡슐화의 기초가 됩니다. 다음 단계는 getter 및 setter 함수를 통해 제어된 접근을 제공하는 것입니다.
챌린지
쉬움불투명 포인터(opaque pointer) 패턴을 보여주는 Timer 모듈을 만들어 보겠습니다. 구조체 정의를 소스 파일 내부에 숨겨서, 모듈을 사용하는 어떤 코드에서도 내부 멤버를 완전히 볼 수 없게 만드는 연습을 할 것입니다.
세 개의 파일을 생성하게 됩니다:
timer.h: 이것은 공개 인터페이스입니다. 전방 선언(forward declaration)만을 사용하여 불투명한Timer타입을 선언하세요. 여기에는 구조체 본문이 없어야 합니다! 또한 두 개의 함수를 선언하세요:create_timer(초를 나타내는 정수를 받아 Timer 포인터를 반환)와free_timer(Timer 포인터를 받아 메모리를 정리).TIMER_H심볼을 사용하여 인클루드 가드(include guards)를 사용하세요.timer.c: 이곳에 비밀이 담깁니다. 두 개의 숨겨진 멤버int seconds와int running(실행 중이면 1, 중지됨이면 0 사용)을 가진 실제struct Timer를 정의하세요. 구조체를 할당하고, 제공된 값으로seconds를 초기화하며,running을 1로 설정하는 생성자를 구현하세요. 메모리를 해제하는 소멸자를 구현하세요.main.c: Timer 모듈을 사용하여 타이머를 생성하고 성공적으로 생성되었는지 확인하세요. 구조체 멤버가 숨겨져 있기 때문에 직접 접근할 수 없습니다. 이것이 바로 핵심입니다! 단순히 생성을 확인하는 메시지를 출력한 다음, 타이머를 해제하고 정리 메시지를 출력하세요.
하나의 입력을 받게 됩니다: 타이머를 초기화할 초 수(정수)입니다.
메인 파일에서 제공된 초 값으로 타이머를 생성하세요. 생성 메시지를 출력한 다음, 타이머를 해제하고 확인 메시지를 출력하세요.
출력은 다음 형식을 따르세요:
Timer created
Timer freed여기서 핵심 통찰은 main.c가 Timer 포인터를 다룰 수는 있지만 seconds나 running에 직접 접근할 방법이 없다는 것입니다. main.c에서 t->seconds를 작성하려고 시도하면 구조체 본문이 timer.c에만 정의되어 있기 때문에 컴파일러 오류가 발생합니다. 이것이 진정한 캡슐화입니다. 구현 세부 사항이 모듈 사용자로부터 완전히 숨겨집니다.
직접 해보기
#include <stdio.h>
#include "timer.h"
int main() {
int seconds;
scanf("%d", &seconds);
// TODO: 제공된 seconds 값을 사용하여 타이머를 생성하세요
// TODO: "Timer created"를 출력하세요
// TODO: 타이머를 해제하세요
// TODO: "Timer freed"를 출력하세요
return 0;
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.