Определение непрозрачных структур
Часть раздела Объектно-ориентированное программирование путешествия по C на Coddy. Урок 18 из 61.
Теперь, когда ты понимаешь концепцию непрозрачных указателей, давай посмотрим, как завершить этот шаблон. Заголовочный файл объявляет о существовании типа, но именно в файле исходного кода определяется его фактическое содержимое.
Вот полная настройка. Сначала заголовочный файл только с предварительным объявлением:
// counter.h
#ifndef COUNTER_H
#define COUNTER_H
typedef struct Counter Counter; // Неполный тип
Counter *create_counter(int start);
void free_counter(Counter *c);
#endif
Затем исходный файл содержит фактическое определение структуры:
// counter.c
#include "counter.h"
#include <stdlib.h>
struct Counter {
int value; // Скрыто от внешнего кода!
int step;
};
Counter *create_counter(int start) {
Counter *c = malloc(sizeof(Counter));
c->value = start;
c->step = 1;
return c;
}
void free_counter(Counter *c) {
free(c);
}
Главное: struct Counter { ... } встречается только в файле .c. Любой файл, который включает counter.h, знает, что Counter существует, но не может видеть value или step. Попытка написать c->value в main.c приведёт к ошибке компилятора: члены структуры действительно невидимы.
Это разделение — основа инкапсуляции в C. Следующий шаг — предоставить контролируемый доступ с помощью функций получения и установки значений.
Задание
ЛегкоСоздадим модуль Timer, демонстрирующий шаблон непрозрачного указателя. Ты потренируешься скрывать определение структуры в исходном файле, делая её внутренние поля совершенно недоступными для кода, использующего твой модуль.
Ты создашь три файла:
timer.h: это публичный интерфейс. Объяви непрозрачный типTimer, используя только предварительное объявление: здесь не должно быть тела структуры! Также объяви две функции:create_timer(принимает целое число секунд и возвращает указатель на Timer) иfree_timer(принимает указатель на Timer и освобождает память). Используй защиту от повторного включения с символомTIMER_H.timer.c: здесь хранится секрет. Определи настоящуюstruct Timerс двумя скрытыми полями:int secondsиint running(используй 1 для работающего состояния и 0 для остановленного). Реализуй конструктор, чтобы выделить память под структуру, инициализироватьsecondsпереданным значением и установитьrunningв 1. Реализуй деструктор, чтобы освободить память.main.c: используй модуль Timer, чтобы создать таймер и убедиться, что он успешно создан. Поскольку поля структуры скрыты, обращаться к ним напрямую нельзя. В этом и заключается суть! Просто выведи сообщение, подтверждающее создание, затем освободи память таймера и выведи сообщение об очистке.
На вход будет подано одно значение: количество секунд (целое число), которым нужно инициализировать таймер.
В главном файле создай таймер, используя переданное значение секунд. Выведи сообщение о создании, затем освободи память таймера и выведи подтверждение.
Выведи результат в следующем формате:
Timer created
Timer freedГлавный вывод здесь в том, что main.c может работать с указателями на Timer, но не имеет возможности обращаться напрямую к seconds или running. Попытка написать t->seconds в main.c приведёт к ошибке компилятора, потому что тело структуры определено только в timer.c. Это и есть настоящая инкапсуляция: детали реализации полностью скрыты от пользователей модуля.
Попробуйте сами
#include <stdio.h>
#include "timer.h"
int main() {
int seconds;
scanf("%d", &seconds);
// TODO: Создайте таймер с заданным значением секунд
// TODO: Выведите "Timer created"
// TODO: Освободите память, выделенную для таймера
// TODO: Выведите "Timer freed"
return 0;
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы модульного программирования
Заголовочные файлыСтражи включенияИсходные файлыСтатические функцииПовторение: Модульный калькулятор4Инкапсуляция
Концепция непрозрачных указателейОпределение непрозрачных структурГеттеры и сеттерыВалидация в сеттерахИтоги: Секретный ящик2Объекты и методы
Структуры как объектыУказатель 'Self'Константная корректностьУказатель против значенияВспомогательные методыИтоги: Point Manager5Проект: Простой банковский счет
Настройка проектаРеализация счета3Жизненный цикл объекта
Паттерн «Конструктор»Паттерн «Деструктор»Инициализация в стекеГлубокое копированиеПовторение: String Wrapper6Наследование через композицию
Встраивание структурПравило первого элементаДоступ к элементам родителяUpcastingПовторение: Иерархия фигур9Проект: Рисование фигур
Обзор проектаРеализация кругаРеализация прямоугольникаПолиморфное использованиеКонтейнер фигурПотренируйтесь самостоятельно: Онлайн-компилятор C