Menu
Coddy logo textTech

Встраивание структур

Часть раздела Object Oriented Programming путешествия по C на Coddy — урок 28 из 61.

В объектно-ориентированных языках, таких как C++ или Java, наследование позволяет классу приобретать свойства родительского класса. В языке C нет встроенного наследования, но мы можем имитировать его, используя технику под названием композиция — помещение одной структуры struct внутрь другой.

Идея проста: если Child нуждается во всех свойствах Parent, мы встраиваем структуру Parent как поле Child.

typedef struct {
    int id;
    char name[50];
} Parent;

typedef struct {
    Parent parent;  // Вложенная структура
    int grade;
} Child;

Здесь Child содержит всё, что есть у Parent, плюс своё собственное поле grade. Это композиция — дочерний объект «имеет» (has a) родителя, а не «является» (is a) родителем, но эффект аналогичен наследованию.

Чтобы получить доступ к членам родителя через экземпляр дочернего класса, используйте оператор точки дважды:

Child c;
c.parent.id = 101;
c.parent.name[0] = 'A';
c.grade = 5;

Этот паттерн служит основой для создания иерархий типов в языке C. Встраивая базовую структуру struct в качестве первого члена, мы открываем доступ к мощным техникам, которые рассмотрим в следующих уроках.

challenge icon

Задание

Легко

Давайте создадим простую систему управления сотрудниками, которая демонстрирует вложение структур — основу наследования в C.

Вы создадите иерархию, в которой Employee содержит Person. Это отражает принцип работы наследования: сотрудник «является» человеком с дополнительной информацией, связанной с работой. Встраивая структуру Person внутрь Employee, вы получаете все свойства человека плюс поля, специфичные для сотрудника.

Вы организуете свой код в трех файлах:

  • types.h: Определите здесь обе структуры с использованием include guards. Сначала создайте структуру Person с двумя полями: name (массив символов из 50 элементов) и age (целое число). Затем определите структуру Employee, которая включает Person в качестве первого члена и добавляет поле employee_id (целое число).
  • types.c: Реализуйте функцию с именем print_employee, которая принимает указатель на Employee и выводит информацию о нем. Обращайтесь к данным встроенного человека, используя синтаксис цепочки точек/стрелок, который вы изучили.
  • main.c: Создайте переменную типа Employee, заполните все ее поля (включая имя и возраст встроенного человека) и используйте функцию печати для отображения информации.

Вы получите три входных значения: имя сотрудника (строка), его возраст (целое число) и его ID сотрудника (целое число).

Ваша функция print_employee должна выводить информацию о сотруднике в следующем формате:

Employee: Alice
Age: 28
ID: 1001

Где Alice — это имя, 28 — возраст, а 1001 — ID сотрудника из ваших входных данных.

Не забудьте обращаться к членам встроенной структуры через родительский член — например, чтобы добраться до имени, вам нужно сначала обратиться к члену person.

Шпаргалка

В языке C нет встроенного наследования, но его можно имитировать с помощью композиции — вложения одной структуры в другую.

Чтобы создать отношение «родитель-потомок», вложите родительскую структуру как поле в дочернюю структуру:

typedef struct {
    int id;
    char name[50];
} Parent;

typedef struct {
    Parent parent;  // Embedded struct
    int grade;
} Child;

Дочерняя структура содержит все свойства родительской, а также свои собственные дополнительные поля. Это представляет отношение «содержит в себе» (has a).

Для доступа к членам вложенной структуры используйте оператор «точка» дважды:

Child c;
c.parent.id = 101;
c.parent.name[0] = 'A';
c.grade = 5;

При работе с указателями используйте оператор «стрелка» для доступа к членам вложенной структуры:

Child *ptr = &c;
ptr->parent.id = 101;
ptr->grade = 5;

Вложение базовой структуры в качестве первого члена является распространенным паттерном, который позволяет использовать продвинутые техники для построения иерархий типов в C.

Попробуйте сами

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

int main() {
    // Чтение входных данных
    char name[50];
    int age;
    int employee_id;
    
    fgets(name, 50, stdin);
    name[strcspn(name, "\n")] = '\0';  // Удаление символа новой строки
    scanf("%d", &age);
    scanf("%d", &employee_id);
    
    // TODO: Создайте переменную типа Employee
    
    // TODO: Заполните имя и возраст вложенной структуры person
    // Подсказка: Используйте strcpy для имени, доступ через employee.person.name
    
    // TODO: Установите employee_id
    
    // TODO: Вызовите print_employee с указателем на вашего сотрудника
    
    return 0;
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Object Oriented Programming