Gettery i settery
Część sekcji Programowanie obiektowe ścieżki C w Coddy. Lekcja 19 z 61.
W przypadku nieprzezroczystych wskaźników składowe struktury są ukryte przed kodem zewnętrznym. Ale jeśli kod zewnętrzny nie może uzyskać bezpośredniego dostępu do danych, jak możemy je odczytywać lub modyfikować? Odpowiedzią są funkcje odczytujące i ustawiające: publiczne interfejsy zapewniające kontrolowany dostęp do prywatnych danych.
Getter zwraca wartość ukrytego składowego:
// counter.h
int counter_get_value(const Counter *c);
// counter.c
int counter_get_value(const Counter *c) {
return c->value;
}
Setter modyfikuje ukryty element:
// 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;
}
Zwróć uwagę na konwencję nazewnictwa: poprzedzaj nazwy funkcji nazwą typu (counter_), aby uniknąć konfliktów i zapewnić przejrzystość API. Gettery używają wskaźników const, ponieważ nie modyfikują obiektu.
Teraz zewnętrzny kod może bezpiecznie korzystać z ukrytych danych:
// 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
Ten wzorzec daje ci pełną kontrolę nad sposobem dostępu do danych: to podstawa, na której oprzemy się w następnej lekcji, dodając logikę walidacji do setterów.
Wyzwanie
ŁatwyZbudujmy moduł Score, który wykorzystuje wzorzec nieprzezroczystego wskaźnika z funkcjami pobierającą i ustawiającą. Utworzysz ukryty licznik punktów, z którym kod zewnętrzny będzie mógł wchodzić w interakcję wyłącznie za pośrednictwem udostępnionego przez Ciebie publicznego interfejsu.
Utworzysz trzy pliki:
score.h: Twój publiczny interfejs. Zadeklaruj nieprzezroczysty typScoreza pomocą deklaracji wyprzedzającej (bez treści struktury!). Zadeklaruj następujące funkcje:create_score: przyjmuje liczbę całkowitą oznaczającą początkową liczbę punktów i zwraca wskaźnik do Scorefree_score: przyjmuje wskaźnik do Score i zwalnia pamięćscore_get_points: funkcja pobierająca, która przyjmujeconst Score *i zwraca bieżącą liczbę punktówscore_set_points: funkcja ustawiająca, która przyjmujeScore *i liczbę całkowitą, aktualizując wartość punktów
SCORE_H.score.c: Zdefiniuj właściwą strukturęstruct Scorez jednym ukrytym polem:int points. Zaimplementuj wszystkie cztery funkcje. Funkcja pobierająca powinna zwracać ukrytą wartość, a funkcja ustawiająca powinna ją aktualizować. Pamiętaj, że funkcje pobierające używają wskaźnikówconst, ponieważ nie modyfikują obiektu.main.c: Zademonstruj działanie modułu, tworząc wynik, odczytując jego wartość, modyfikując ją za pomocą funkcji ustawiającej i ponownie ją odczytując.
Otrzymasz dwa wejścia: początkową liczbę punktów (liczbę całkowitą) oraz nową wartość punktów (liczbę całkowitą), którą należy ustawić.
W pliku głównym utwórz obiekt Score z początkową liczbą punktów, wypisz bieżącą wartość za pomocą funkcji pobierającej, zaktualizuj ją za pomocą funkcji ustawiającej, przekazując nową wartość, wypisz zaktualizowaną wartość, a następnie zwolnij pamięć zajmowaną przez wynik i wypisz potwierdzenie.
Wypisz wynik w tym formacie:
Initial: {points}
Updated: {points}
FreedNa przykład dla wejść 100 i 250 wynik będzie następujący:
Initial: 100
Updated: 250
FreedZwróć uwagę, że main.c nie może uzyskać bezpośredniego dostępu do points. Musi korzystać z funkcji pobierającej i ustawiającej. To właśnie enkapsulacja w praktyce: masz pełną kontrolę nad tym, jak można odczytywać i modyfikować ukryte dane.
Spróbuj swoich sił
#include <stdio.h>
#include "score.h"
int main() {
int initial_points, new_points;
scanf("%d", &initial_points);
scanf("%d", &new_points);
// TODO: Utwórz obiekt Score z initial_points
// TODO: Wypisz wartość początkową za pomocą gettera
// Format: "Initial: {points}"
// TODO: Zaktualizuj wynik za pomocą settera, używając new_points
// TODO: Wypisz zaktualizowaną wartość za pomocą gettera
// Format: "Updated: {points}"
// TODO: Zwolnij pamięć zajmowaną przez obiekt Score i wypisz "Freed"
return 0;
}
Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.
Wszystkie lekcje w sekcji Programowanie obiektowe
1Podstawy programowania modularnego
Pliki nagłówkoweZabezpieczenia przed wielokrotnym dołączeniemPliki źródłoweFunkcje statycznePodsumowanie: kalkulator modularny4Enkapsulacja
Koncepcja niejawnych wskaźnikówDefiniowanie niejawnych strukturGettery i setteryWalidacja w setterachPowtórka: tajemnicze pudełko2Obiekty i metody
Struktury jako obiektyWskaźnik „self”Poprawność constWskaźnik czy wartośćMetody pomocniczePodsumowanie: menedżer punktów5Projekt: Proste konto bankowe
Konfiguracja projektuImplementacja konta8Polimorfizm
Wskaźniki do funkcji w strukturachSymulowanie metodKoncepcja interfejsuImplementowanie interfejsówIteracja polimorficznaPodsumowanie: Greeter11Wzorce projektowe w C
Wzorzec SingletonWzorzec fabrykiWzorzec iteratoraPodsumowanie: fabryka loggera3Cykl życia obiektu
Wzorzec konstruktoraWzorzec destruktoraInicjalizacja na stosieKopia głębokaPodsumowanie: klasa opakowująca ciąg znaków6Dziedziczenie przez kompozycję
Osadzanie strukturZasada pierwszego elementuDostęp do elementów klasy nadrzędnejKonwersja w górę hierarchiiPodsumowanie: hierarchia kształtów9Projekt: Rysownik kształtów
Przegląd projektuImplementacja kołaImplementacja prostokątaZastosowanie polimorfizmuKontener kształtówPoćwicz samodzielnie: Kompilator C online