다형적 순회
Coddy C 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 61개 중 42번째.
인터페이스를 만들고 서로 다른 구체적인 functions로 이를 Implement하는 방법을 배웠습니다. 진정한 보상은 서로 다른 객체의 모음을 일관된 방식으로 다룰 수 있을 때 얻을 수 있습니다. 즉, 어떤 구체적인 동작이 연결되어 있는지와 관계없이 객체들을 순회하며 각각에 동일한 function pointer를 호출할 수 있습니다.
각각 고유한 execute 함수가 할당된 Action 구조체의 배열이 있다고 상상해 보세요.
typedef void (*ExecuteFunc)(void);
typedef struct {
const char* name;
ExecuteFunc execute;
} Action;
void jump(void) { printf("Jumping!\n"); }
void run(void) { printf("Running!\n"); }
void rest(void) { printf("Resting...\n"); }이러한 actions의 array를 만들고, each 항목을 서로 다른 function에 연결한 다음, 간단한 for loop로 이를 순회할 수 있습니다:
int main() {
Action actions[3] = {
{ "Jump", jump },
{ "Run", run },
{ "Rest", rest }
};
for (int i = 0; i < 3; i++) {
printf("%s: ", actions[i].name);
actions[i].execute();
}
return 0;
}반복문은 각 작업이 내부적으로 무엇을 하는지 알거나 신경 쓰지 않습니다. 단순히 각 요소에서 execute()를 호출합니다.
이것이 다형성이 작동하는 방식입니다. 동일한 코드가 완전히 다른 동작을 하는 객체를 처리합니다. 새로운 동작 유형을 추가해도 반복 로직을 변경할 필요가 없습니다. array에 요소를 하나 더 추가하기만 하면 됩니다.
챌린지
쉬움다형성 반복을 보여 주는 Task 관리 시스템을 만들어 봅시다. 공통 인터페이스를 공유하지만 서로 다른 동작을 실행하는 객체 컬렉션을 처리합니다.
코드를 세 개의 파일로 구성합니다:
task.h: 여기에서 task 인터페이스를 Define합니다. 매개변수를 받지 않고 아무것도 반환하지 않는TaskFunc라는 function pointer type을 Create합니다. 그런 다음name(const char*)과TaskFunctype의runfunction pointer를 containing하는Taskstruct를 Define합니다.task.c: 서로 다른 종류의 작업을 나타내는 세 개의 서로 다른 task functions를 Implement합니다:backup_task:Backing up data...를 출력합니다.cleanup_task:Cleaning up files...를 출력합니다.report_task:Generating report...를 출력합니다.
main.c: 여기에서 모든 것을 함께 구성합니다. 각각 서로 다른 task function에 연결된Taskstructs의 array를 Create합니다. 그런 다음 array를 Iterate하며 각 task를 polymorphically execute합니다. 각 task에 대해 해당 이름을 출력한 다음runfunction을 call합니다.
프로그램은 실행할 task의 수(1, 2 또는 3)라는 하나의 입력을 받습니다.
정확히 세 개의 task를 다음 order로 containing하는 array를 Create합니다: Backup이라는 이름의 backup task, Cleanup이라는 이름의 cleanup task, 그리고 Report라는 이름의 report task입니다. 입력 count에 따라 array의 beginning부터 해당 수만큼의 task만 Iterate합니다.
반복하는 각 task에 대해 task의 이름 뒤에 콜론과 공백을 출력한 다음 해당 run function을 call합니다.
입력이 2일 때의 예시 출력:
Backup: Backing up data...
Cleanup: Cleaning up files...입력이 3일 때의 예시 출력:
Backup: Backing up data...
Cleanup: Cleaning up files...
Report: Generating report...핵심 통찰은 loop가 각 task가 무엇을 하는지 알 필요가 없다는 것입니다. 단순히 이름을 출력하고 각 element에서 run()을 call합니다. 동일한 iteration code가 모든 task type을 uniform하게 처리합니다. header file에서 include guards를 사용하는 것을 잊지 마세요.
직접 해보기
#include <stdio.h>
#include "task.h"
// task.c에 구현된 태스크 함수들을 선언
void backup_task(void);
void cleanup_task(void);
void report_task(void);
int main() {
int count;
scanf("%d", &count);
// TODO: 다음 순서로 3개의 Task 구조체 배열을 생성:
// 1. backup_task를 사용하는 "Backup"이라는 이름의 Backup 태스크
// 2. cleanup_task를 사용하는 "Cleanup"이라는 이름의 Cleanup 태스크
// 3. report_task를 사용하는 "Report"이라는 이름의 Report 태스크
// TODO: 배열에서 'count'개의 태스크를 반복 처리
// 각 태스크에 대해 "<name>: "을 출력한 다음 해당 run 함수를 호출
return 0;
}
이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.
객체 지향 프로그래밍의 모든 레슨
직접 연습해 보세요: 온라인 C 컴파일러