Menu
Coddy logo textTech

첫 번째 멤버 규칙

Coddy C 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 61개 중 29번째.

struct를 다른 struct의 first member로 embedded하면 강력한 일이 발생합니다. 바깥쪽 struct의 memory address는 해당 first member의 memory address와 동일합니다. 이는 C 표준에 의해 보장됩니다.

이전 예제를 살펴보세요:

typedef struct {
    int id;
} Parent;

typedef struct {
    Parent parent;  // 첫 번째 멤버
    int grade;
} Child;

Child 변수를 생성하면 Parent member는 Child의 memory 맨 앞에 위치합니다. 이는 Child를 가리키는 포인터가 해당 ChildParent member를 가리키는 포인터와 정확히 같은 address를 가리킨다는 의미입니다.

Child c;
Child* child_ptr = &c;
Parent* parent_ptr = (Parent*)child_ptr;  // 안전한 캐스트!

두 포인터는 동일한 address를 가리킵니다. 따라서 Parent*를 필요로 하는 어떤 function에도 Child*를 전달할 수 있습니다:

void print_id(Parent* p) {
    printf("ID: %d\n", p->id);
}

// main에서:
Child c;
c.parent.id = 42;
print_id((Parent*)&c);  // 완벽하게 작동합니다

이 기법은 C에서 상속의 기반입니다. 기본 타입을 위해 작성된 function은 base가 먼저 embedded되어 있기만 하면 어떤 파생 타입에서도 작동할 수 있습니다. memory layouts가 perfectly align되므로 cast는 안전합니다.

challenge icon

챌린지

쉬움

간단한 동물 계층 구조를 만들어 first member 규칙을 살펴보겠습니다. 기본 Animal struct와 파생 Dog struct를 만들고, Dog에 대한 포인터를 Animal에 대한 포인터로 안전하게 cast하는 방법을 확인합니다.

적용할 핵심 내용은 다음과 같습니다. AnimalDog의 first member일 때 두 struct는 동일한 시작 memory 주소를 공유합니다. 따라서 포인터를 cast하면 Dog*Animal*을 필요로 하는 어떤 function에도 전달할 수 있습니다.

코드를 세 개의 파일로 구성합니다.

  • animal.h: include guard와 함께 두 struct를 Define합니다. Animal struct에는 단일 field인 legs를 둡니다(다리의 개수를 나타내는 정수). Dog struct는 Animalfirst member로 embedded하고, name field(50 characters의 character array)를 추가해야 합니다. 또한 Animal* parameter를 받는 print_animal function을 Declare합니다.
  • animal.c: print_animal function을 Implement합니다. 이 function은 base type과 함께 작동하며, Animal에 대해서만 알고 동물의 다리 수를 Print합니다.
  • main.c: Dog variable을 Create하고 해당 field를 채웁니다(embedded된 animal의 legs와 dog의 name 모두). 그런 다음 Dog*Animal*로 cast하여 print_animal에 전달함으로써 first member 규칙을 보여 줍니다. 전체 모습을 보여 주기 위해 dog의 name도 별도로 Print합니다.

두 개의 입력을 받습니다. dog의 name(string)과 number of legs(integer)입니다.

출력은 다음과 같은 형태여야 합니다.

Dog: Buddy
Legs: 4

여기서 Buddy는 dog의 name이고 4는 다리의 개수입니다. 먼저 main.c에서 dog의 name을 Print한 다음, cast된 포인터와 함께 print_animal을 call하여 다리 수를 표시합니다.

이는 base type(Animal)을 위해 작성된 function이 포인터 cast를 통해 derived type(Dog)와도 원활하게 작동할 수 있음을 보여 줍니다. 이는 C에서 inheritance의 foundation입니다.

직접 해보기

#include <stdio.h>
#include <string.h>
#include "animal.h"

int main() {
    // 입력 읽기
    char name[50];
    int legs;
    scanf("%s", name);
    scanf("%d", &legs);
    
    // TODO: Dog 변수 생성
    
    // TODO: strcpy를 사용하여 dog의 이름 설정
    
    // TODO: 다리 수 설정 (임베디드 Animal을 통해 접근)
    
    // TODO: "Dog: <name>" 형식으로 dog의 이름 출력
    
    // TODO: Dog*를 Animal*로 캐스팅하고 print_animal 호출
    // 이것은 first member rule을 보여줍니다!
    
    return 0;
}
quiz icon실력 점검

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

객체 지향 프로그래밍의 모든 레슨

직접 연습해 보세요: 온라인 C 컴파일러