Menu
Coddy logo textTech

업캐스팅

Coddy C 여정의 Object Oriented Programming 섹션에 포함된 레슨 — 61개 중 31번째.

업캐스팅(Upcasting)은 구체적인(파생된) 타입을 더 일반적인(기본) 타입으로 취급하는 행위입니다. C의 구성(composition) 모델에서 이는 기본 타입을 포함하는 struct에 대한 포인터를 기본 타입을 기대하는 함수에 전달하는 것을 의미합니다.

Vehicle 기본 구조체와 이를 포함하는 Car를 고려해 봅시다:

typedef struct {
    int speed;
} Vehicle;

typedef struct {
    Vehicle vehicle;  // 첫 번째 멤버인 기본 구조체
    int doors;
} Car;

이제 모든 차량에 작동하는 일반적인 함수를 상상해 보세요:

void accelerate(Vehicle* v, int amount) {
    v->speed += amount;
}

첫 번째 멤버 규칙 덕분에, Car*Vehicle*로 캐스팅하여 이 함수에 전달할 수 있습니다:

Car my_car = {{0}, 4};  // 속도=0, 문=4
accelerate((Vehicle*)&my_car, 50);
printf("Speed: %d\n", my_car.vehicle.speed);  // 출력: 50

이것은 업캐스팅(upcasting)입니다 — 구체적인 타입에서 일반적인 타입으로 "위로" 이동하는 것입니다. accelerate 함수는 자신이 Car와 작업하고 있다는 사실을 알지 못하며, 단지 Vehicle로만 인식합니다. 이를 통해 기본 타입을 기반으로 동작하면서, 해당 타입을 포함하는 모든 파생 타입을 수용할 수 있는 재사용 가능한 코드를 작성할 수 있습니다.

challenge icon

챌린지

쉬움

업캐스팅(upcasting)이 실제로 어떻게 작동하는지 보여주는 간단한 운송 시스템을 구축해 보겠습니다. 기본 Vehicle 타입과 더 구체적인 Motorcycle 타입을 만든 다음, 포인터 캐스팅을 통해 제네릭 함수가 두 타입 모두와 어떻게 작동하는지 보여줄 것입니다.

업캐스팅의 강력함은 기본 타입을 위한 함수를 작성하면, 해당 타입을 포함하는 모든 파생 타입과 원활하게 작동한다는 점에 있습니다. 오토바이는 하나의 "탈것(vehicle)"이므로, Vehicle*를 기대하는 모든 함수는 이를 처리할 수 있어야 합니다.

코드는 세 개의 파일로 구성됩니다:

  • vehicle.h: 인클루드 가드(include guards)를 사용하여 구조체 계층을 정의합니다. 두 개의 필드, 즉 speed(현재 속도를 나타내는 정수)와 max_speed(탈것의 최고 속도를 나타내는 정수)를 가진 Vehicle 구조체를 만듭니다. 그런 다음 Vehicle을 첫 번째 멤버로 포함하고 has_sidecar 필드(1은 있음, 0은 없음을 나타내는 정수)를 추가하는 Motorcycle 구조체를 정의합니다. 두 개의 함수를 선언합니다: Vehicle*와 속도를 높일 양을 인자로 받는 boost 함수, 그리고 Motorcycle*를 인자로 받는 print_motorcycle 함수입니다.
  • vehicle.c: 두 함수를 구현합니다. boost 함수는 주어진 양만큼 탈것의 속도를 높여야 하지만, max_speed를 초과할 수 없습니다. 만약 새로운 속도가 최고 속도를 초과하면 max_speed로 설정하십시오. print_motorcycle 함수는 포함된 탈것 데이터를 포함하여 오토바이의 모든 정보를 표시해야 합니다.
  • main.c: Motorcycle을 생성하고 모든 필드를 초기화합니다. 그런 다음 boost 함수를 호출하여 업캐스팅을 시연합니다. Motorcycle*Vehicle*로 캐스팅하여 이 제네릭 함수에 전달하십시오. 부스팅 후에는 오토바이의 정보를 출력하여 결과를 확인합니다.

네 개의 입력을 받게 됩니다: 오토바이의 초기 속도(initial speed), 최고 속도(max speed), 사이드카 유무(has a sidecar) (1 또는 0), 그리고 부스트 양(boost amount)입니다.

출력은 다음과 같아야 합니다:

Speed: 75
Max Speed: 120
Sidecar: Yes

여기서 75는 부스팅 후의 속도(초기 50 + 부스트 25)이고, 120은 최고 속도이며, Yes 또는 No는 오토바이에 사이드카가 있는지 여부를 나타냅니다. 부스트가 속도를 최고 속도 이상으로 높이려고 하면 속도는 최고 속도에서 제한되어야 합니다.

여기서 핵심 학습 포인트는 boost 함수가 오토바이에 대해 전혀 모른다는 것입니다. 이 함수는 오토바이가 아닌 Vehicle하고만 작동합니다. 하지만 업캐스팅을 통해 오토바이는 이 제네릭 함수를 사용하여 포함된 탈것 데이터를 수정할 수 있습니다.

치트 시트

업캐스팅(Upcasting)은 기본 타입을 포함하는 구조체에 대한 포인터를 기본 타입을 기대하는 함수에 전달함으로써, 특정(파생) 타입을 더 일반적인(기본) 타입으로 취급합니다.

기본 구조체와 이를 첫 번째 멤버로 포함하는 파생 구조체를 정의합니다:

typedef struct {
    int speed;
} Vehicle;

typedef struct {
    Vehicle vehicle;  // 기본 타입을 첫 번째 멤버로 포함
    int doors;
} Car;

기본 타입으로 작동하는 함수를 생성합니다:

void accelerate(Vehicle* v, int amount) {
    v->speed += amount;
}

파생 타입 포인터를 기본 타입 포인터로 캐스팅하여 함수를 호출합니다:

Car my_car = {{0}, 4};  // speed=0, doors=4
accelerate((Vehicle*)&my_car, 50);
printf("Speed: %d\n", my_car.vehicle.speed);  // 출력: 50

이를 통해 기본 타입을 포함하는 모든 파생 타입을 허용하면서, 기본 타입에서 작동하는 재사용 가능한 코드를 작성할 수 있습니다.

직접 해보기

#include <stdio.h>
#include "vehicle.h"

int main() {
    int initial_speed, max_speed, has_sidecar, boost_amount;
    
    // 입력값 읽기
    scanf("%d", &initial_speed);
    scanf("%d", &max_speed);
    scanf("%d", &has_sidecar);
    scanf("%d", &boost_amount);
    
    // TODO: Motorcycle을 생성하고 모든 필드를 초기화하세요
    // 주의: Motorcycle은 첫 번째 멤버로 Vehicle을 포함합니다
    
    // TODO: boost를 호출하여 업캐스팅(upcasting)을 시연하세요
    // Motorcycle*를 Vehicle*로 캐스팅하여 boost 함수에 전달하세요
    
    // TODO: 오토바이의 정보를 출력하세요
    
    return 0;
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

Object Oriented Programming의 모든 레슨