Menu
Coddy logo textTech

Геттеры и сеттеры

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

При использовании непрозрачных указателей члены структуры скрыты от внешнего кода. Но если внешний код не может получить прямой доступ к данным, как нам их читать или изменять? Ответ заключается в функциях-геттерах и сеттерах — публичных интерфейсах, которые обеспечивают контролируемый доступ к приватным данным.

Геттер возвращает значение скрытого члена:

// counter.h
int counter_get_value(const Counter *c);

// counter.c
int counter_get_value(const Counter *c) {
    return c->value;
}

Сеттер изменяет скрытый член:

// counter.h
void counter_set_value(Counter *c, int new_value);

// counter.c
void counter_set_value(Counter *c, int new_value) {
    c->value = new_value;
}

Обратите внимание на соглашение об именовании: добавляйте к функциям префикс с именем типа (counter_), чтобы избежать конфликтов и сделать API понятным. Геттеры используют const указатели, так как они не изменяют объект.

Теперь внешний код может безопасно взаимодействовать со скрытыми данными:

// main.c
Counter *c = create_counter(10);
printf("%d\n", counter_get_value(c));  // 10
counter_set_value(c, 25);
printf("%d\n", counter_get_value(c));  // 25

Этот паттерн дает вам полный контроль над тем, как осуществляется доступ к данным — это основа, на которой мы будем строить в следующем уроке, когда добавим логику валидации в сеттеры.

challenge icon

Задание

Легко

Давайте создадим модуль Score, который использует паттерн непрозрачного указателя (opaque pointer) с функциями геттерами и сеттерами. Вы создадите скрытый трекер счета, где внешний код сможет взаимодействовать с данными только через предоставленный вами публичный интерфейс.

Вы создадите три файла:

  • score.h: Ваш публичный интерфейс. Объявите непрозрачный тип Score, используя опережающее объявление (без тела структуры!). Объявите следующие функции:
    • create_score — принимает целое число для начальных очков и возвращает указатель на Score
    • free_score — принимает указатель на Score и освобождает память
    • score_get_points — геттер, который принимает const Score * и возвращает текущие очки
    • score_set_points — сеттер, который принимает Score * и целое число, обновляя значение очков
    Используйте include guards с символом SCORE_H.
  • score.c: Определите саму struct Score с единственным скрытым членом: int points. Реализуйте все четыре функции. Ваш геттер должен возвращать скрытое значение, а сеттер — обновлять его. Помните, что геттеры используют указатели const, так как они не изменяют объект.
  • main.c: Продемонстрируйте работу вашего модуля, создав счет, прочитав его значение, изменив его через сеттер и прочитав снова.

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

В вашем основном файле создайте Score с начальными очками, выведите текущее значение с помощью геттера, обновите его с помощью сеттера новым значением, выведите обновленное значение, затем освободите score и выведите подтверждение.

Выводите результат в следующем формате:

Initial: {points}
Updated: {points}
Freed

Например, при входных данных 100 и 250 результат будет таким:

Initial: 100
Updated: 250
Freed

Обратите внимание, что main.c не может получить прямой доступ к points — он должен использовать ваши функции геттера и сеттера. Это инкапсуляция в действии: вы точно контролируете, как скрытые данные могут быть прочитаны и изменены.

Шпаргалка

При использовании непрозрачных указателей (opaque pointers) члены структуры скрыты от внешнего кода. Чтобы получить доступ к этим приватным данным или изменить их, используйте функции геттеры (getter) и сеттеры (setter).

Геттер возвращает значение скрытого члена и использует указатель const, так как он не изменяет объект:

// counter.h
int counter_get_value(const Counter *c);

// counter.c
int counter_get_value(const Counter *c) {
    return c->value;
}

Сеттер изменяет значение скрытого члена:

// counter.h
void counter_set_value(Counter *c, int new_value);

// counter.c
void counter_set_value(Counter *c, int new_value) {
    c->value = new_value;
}

Используйте соглашение об именовании с именем типа в качестве префикса (counter_), чтобы избежать конфликтов и сделать API более понятным.

Внешний код взаимодействует со скрытыми данными через эти функции:

// main.c
Counter *c = create_counter(10);
printf("%d\n", counter_get_value(c));  // 10
counter_set_value(c, 25);
printf("%d\n", counter_get_value(c));  // 25

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

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

int main() {
    int initial_points, new_points;
    scanf("%d", &initial_points);
    scanf("%d", &new_points);
    
    // TODO: Создать Score с initial_points
    
    // TODO: Вывести начальное значение, используя геттер
    // Формат: "Initial: {points}"
    
    // TODO: Обновить счет, используя сеттер с new_points
    
    // TODO: Вывести обновленное значение, используя геттер
    // Формат: "Updated: {points}"
    
    // TODO: Освободить память score и вывести "Freed"
    
    return 0;
}
quiz iconПроверьте себя

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

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