Definiowanie niejawnych struktur
Część sekcji Programowanie obiektowe ścieżki C w Coddy. Lekcja 18 z 61.
Teraz, gdy rozumiesz pojęcie nieprzezroczystych wskaźników, zobaczmy, jak uzupełnić ten wzorzec. Nagłówek deklaruje istnienie typu, ale to w pliku źródłowym definiujesz, co tak naprawdę się w nim znajduje.
Oto kompletna konfiguracja. Najpierw nagłówek zawierający tylko deklarację wstępną:
// counter.h
#ifndef COUNTER_H
#define COUNTER_H
typedef struct Counter Counter; // Typ niekompletny
Counter *create_counter(int start);
void free_counter(Counter *c);
#endif
Następnie plik źródłowy zawiera właściwą definicję struktury:
// counter.c
#include "counter.h"
#include <stdlib.h>
struct Counter {
int value; // Ukryte przed dostępem z zewnątrz!
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);
}
Najważniejsze: struct Counter { ... } pojawia się tylko w pliku .c. Każdy plik dołączający counter.h wie, że Counter istnieje, ale nie widzi value ani step. Próba zapisania c->value w main.c spowodowałaby błąd kompilatora: składowe są naprawdę niewidoczne.
Ten podział stanowi podstawę enkapsulacji w C. Kolejnym krokiem jest zapewnienie kontrolowanego dostępu za pomocą funkcji pobierających i ustawiających.
Wyzwanie
ŁatwyZbudujmy moduł Timer, który demonstruje wzorzec nieprzezroczystego wskaźnika. Poćwiczysz ukrywanie definicji struktury w pliku źródłowym, dzięki czemu jej wewnętrzne składowe będą całkowicie niewidoczne dla kodu korzystającego z modułu.
Utworzysz trzy pliki:
timer.h: To Twój publiczny interfejs. Zadeklaruj nieprzezroczysty typTimer, używając wyłącznie deklaracji wstępnej: bez definicji ciała struktury! Zadeklaruj też dwie funkcje:create_timer(przyjmuje liczbę całkowitą określającą sekundy i zwraca wskaźnik do Timer) orazfree_timer(przyjmuje wskaźnik do Timer i zwalnia zasoby). Użyj strażników dołączania z symbolemTIMER_H.timer.c: Tutaj kryje się sekret. Zdefiniuj właściwąstruct Timerz dwiema ukrytymi składowymi:int secondsiint running(użyj wartości 1 dla działania i 0 dla zatrzymania). Zaimplementuj konstruktor, który przydzieli pamięć dla struktury, zainicjujesecondspodaną wartością i ustawirunningna 1. Zaimplementuj destruktor, który zwolni pamięć.main.c: Użyj modułu Timer, aby utworzyć timer i potwierdzić, że został utworzony pomyślnie. Ponieważ składowe struktury są ukryte, nie możesz uzyskać do nich bezpośredniego dostępu. Na tym właśnie polega cały sens! Po prostu wypisz komunikat potwierdzający utworzenie, następnie zwolnij timer i wypisz komunikat o zwolnieniu zasobów.
Otrzymasz jedno wejście: liczbę sekund (liczbę całkowitą), od której należy zainicjować timer.
W pliku głównym utwórz timer z podaną liczbą sekund. Wypisz komunikat o utworzeniu, następnie zwolnij timer i wypisz potwierdzenie.
Wypisz dane wyjściowe w tym formacie:
Timer created
Timer freedNajważniejsze jest to, że main.c może korzystać ze wskaźników do Timer, ale nie ma możliwości bezpośredniego dostępu do seconds ani running. Próba zapisania t->seconds w main.c spowodowałaby błąd kompilatora, ponieważ ciało struktury jest zdefiniowane wyłącznie w timer.c. To właśnie prawdziwa enkapsulacja: szczegóły implementacji są całkowicie ukryte przed użytkownikami modułu.
Spróbuj swoich sił
#include <stdio.h>
#include "timer.h"
int main() {
int seconds;
scanf("%d", &seconds);
// TODO: Utwórz timer z podaną wartością seconds
// TODO: Wypisz "Timer created"
// TODO: Zwolnij pamięć timera
// TODO: Wypisz "Timer 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