Паттерн «Конструктор»
Часть раздела Object Oriented Programming путешествия по C на Coddy — урок 12 из 61.
В таких языках, как Java или C++, вы создаете объекты с помощью конструкторов — специальных функций, которые автоматически выделяют память и инициализируют поля. В языке C такой возможности нет, но мы можем имитировать ее с помощью простого паттерна: функции create_.
Функция-конструктор в C обычно выполняет три действия: выделяет память с помощью malloc, инициализирует все поля соответствующими значениями и возвращает указатель на новый объект:
typedef struct {
char *name;
int age;
} Person;
Person *create_person(const char *name, int age) {
Person *p = malloc(sizeof(Person));
p->name = malloc(strlen(name) + 1);
strcpy(p->name, name);
p->age = age;
return p;
}
Функция возвращает указатель, так как объект располагается в куче, а не в стеке. Это означает, что он продолжает существовать после возврата из функции и его можно свободно передавать. Вызывающий код использует его так:
Person *alice = create_person("Alice", 30);
printf("%s is %d years old\n", alice->name, alice->age);
Обратите внимание, как конструктор берет на себя все сложные детали — выделение памяти под структуру, выделение места для строки и копирование данных. Вызывающая сторона просто предоставляет начальные значения и получает готовый к использованию объект. Это инкапсулирует логику создания в одном месте, делая ваш код чище и менее подверженным ошибкам.
Задание
ЛегкоДавайте создадим модуль Book, который использует паттерн конструктора для создания объектов книг в куче. Вы попрактикуетесь в написании функции create_, которая берет на себя все задачи по выделению памяти и инициализации, возвращая готовый к использованию указатель.
Вы создадите три файла:
book.h: Объявите структуруBookс двумя полями:char *title(указатель на динамически выделенную строку) иint pages. Также объявите функцию-конструкторcreate_book, которая принимает строку заголовка и количество страниц, а затем возвращает указатель на вновь созданную структуру Book. Используйте include guards с символомBOOK_H.book.c: Реализуйте функциюcreate_book. Ваш конструктор должен выделить память для самой структуры Book, затем выделить отдельную память для строки заголовка (не забудьте учесть нулевой терминатор), скопировать заголовок в новую память, установить поле pages и вернуть указатель на новую Book.main.c: Используйте ваш конструктор для создания книги и вывода информации о ней.
Вы получите два входных значения: название книги (строка) и количество страниц (целое число).
В вашем основном файле используйте create_book для создания новой книги с предоставленными значениями, а затем выведите информацию о ней в следующем формате:
Title: {title}
Pages: {pages}Например, при входных данных The C Programming Language и 272, вывод будет следующим:
Title: The C Programming Language
Pages: 272Помните, что ваш конструктор инкапсулирует всю логику создания — вызывающая сторона просто предоставляет начальные значения и получает полностью инициализированный объект, готовый к использованию.
Шпаргалка
Функция-конструктор в C имитирует создание объекта путем выделения памяти и инициализации полей. Обычно она следует шаблону именования create_.
Функция-конструктор делает три вещи:
- Выделяет память с помощью
malloc - Инициализирует все поля соответствующими значениями
- Возвращает указатель на новый объект
Пример шаблона конструктора:
typedef struct {
char *name;
int age;
} Person;
Person *create_person(const char *name, int age) {
Person *p = malloc(sizeof(Person));
p->name = malloc(strlen(name) + 1);
strcpy(p->name, name);
p->age = age;
return p;
}
Использование конструктора:
Person *alice = create_person("Alice", 30);
printf("%s is %d years old\n", alice->name, alice->age);
Функция возвращает указатель, потому что объект находится в куче и сохраняется после завершения работы функции. Это инкапсулирует логику создания в одном месте, делая код чище и менее подверженным ошибкам.
Попробуйте сами
#include <stdio.h>
#include <stdlib.h>
#include "book.h"
int main() {
char title[256];
int pages;
// Чтение входных данных
fgets(title, sizeof(title), stdin);
// Удаление символа новой строки, если он есть
for (int i = 0; title[i]; i++) {
if (title[i] == '\n') {
title[i] = '\0';
break;
}
}
scanf("%d", &pages);
// TODO: Используйте create_book для создания новой книги с предоставленными значениями
// TODO: Выведите информацию о книге в требуемом формате:
// Название: {title}
// Страницы: {pages}
// TODO: Не забудьте освободить выделенную память по завершении
return 0;
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Object Oriented Programming
1Основы модульного программирования
Заголовочные файлыСтражи включенияИсходные файлыСтатические функцииПовторение: Модульный калькулятор4Инкапсуляция
Концепция непрозрачных указателейОпределение непрозрачных структурГеттеры и сеттерыВалидация в сеттерахИтоги: Секретный ящик2Объекты и методы
Структуры как объектыУказатель 'Self'Константная корректностьУказатель против значенияВспомогательные методыИтоги: Point Manager5Проект: Простой банковский счет
Настройка проектаРеализация счета3Жизненный цикл объекта
Паттерн «Конструктор»Паттерн «Деструктор»Инициализация в стекеГлубокое копированиеПовторение: String Wrapper6Наследование через композицию
Встраивание структурПравило первого элементаДоступ к элементам родителяUpcastingПовторение: Иерархия фигур9Проект: Рисование фигур
Обзор проектаРеализация круга