Wskaźniki do funkcji w strukturach
Część sekcji Programowanie obiektowe ścieżki C w Coddy. Lekcja 38 z 61.
Do tej pory używaliśmy wskaźników do funkcji jako samodzielnych zmiennych lub przekazywaliśmy je jako argumenty. Kolejnym krokiem w kierunku polimorfizmu jest osadzenie wskaźnika do funkcji bezpośrednio w strukturze, co nadaje jej własne zachowanie.
Gdy struktura zawiera wskaźnik do funkcji, każda instancja może przechowywać inną funkcję. Oznacza to, że dwa obiekty tego samego typu mogą zachowywać się inaczej, gdy wywołasz ich wskaźnik do funkcji:
typedef void (*PrintFunc)(const char*);
typedef struct {
const char* name;
PrintFunc print; // Wskaźnik do funkcji jako składowa
} Printer;Struktura Printer ma teraz dwa elementy: dane (name) i zachowanie (print). Aby jej użyć, podczas inicjalizacji przypisujesz funkcję do wskaźnika:
void loud_print(const char* msg) {
printf("!!! %s !!!\n", msg);
}
int main() {
Printer p;
p.name = "Alert";
p.print = loud_print;
p.print("Hello"); // Wynik: !!! Hello !!!
return 0;
}Zwróć uwagę, że wywołujemy funkcję za pośrednictwem struktury: p.print("Hello"). Wygląda to bardzo podobnie do wywoływania metody na obiekcie w innych językach. Struktura zawiera zarówno swoje dane, jak i funkcję, która na nich operuje.
Ten wzorzec stanowi podstawę polimorfizmu w C: różnym instancjom można przypisać różne funkcje, uzyskując różne zachowania tego samego typu struktury.
Wyzwanie
ŁatwyZbudujmy system Notifier, który pokazuje, jak struktury mogą zawierać własne zachowanie za pomocą wskaźników do funkcji.
Utworzysz dwa pliki, aby uporządkować kod:
notifier.h: Zdefiniuj typ wskaźnika do funkcji o nazwieNotifyFunc, który przyjmuje parametrconst char*i niczego nie zwraca. Następnie zdefiniuj strukturęNotifier, która zawiera polename(typuconst char*) oraz wskaźnik do funkcjinotifytypuNotifyFunc.main.c: Dołącz plik nagłówkowy i zaimplementuj dwie funkcje powiadomień:alert_notify: wyświetla komunikat w formacie:[ALERT] messageinfo_notify: wyświetla komunikat w formacie:[INFO] message
Notifier, przypisz odpowiednią funkcję na podstawie danych wejściowych i wywołaj powiadomienie za pomocą wskaźnika do funkcji w strukturze.
Twój program otrzyma dwa dane wejściowe: typ powiadomienia (1 oznacza alert, 2 — informację) oraz komunikat do wyświetlenia.
Na podstawie typu przypisz odpowiednią funkcję do pola notify swojego obiektu notifier, a następnie wywołaj ją za pośrednictwem struktury, aby wyświetlić komunikat.
Przykładowy wynik, gdy typ wynosi 1, a komunikat to "System starting":
[ALERT] System startingPrzykładowy wynik, gdy typ wynosi 2, a komunikat to "All systems normal":
[INFO] All systems normalPamiętaj, aby użyć strażników dołączania w pliku nagłówkowym i wywołać funkcję za pośrednictwem pola struktury: n.notify(message)
Spróbuj swoich sił
#include <stdio.h>
#include "notifier.h"
// TODO: Zaimplementuj funkcję alert_notify
// Powinna wypisać: [ALERT] message
// TODO: Zaimplementuj funkcję info_notify
// Powinna wypisać: [INFO] message
int main() {
int type;
char message[256];
// Odczytaj dane wejściowe
scanf("%d", &type);
getchar(); // odczytaj znak nowej linii
fgets(message, sizeof(message), stdin);
// Usuń końcowy znak nowej linii z message, jeśli występuje
int len = 0;
while (message[len] != '\0') len++;
if (len > 0 && message[len-1] == '\n') message[len-1] = '\0';
// TODO: Utwórz instancję Notifier
// TODO: Na podstawie type (1 dla alert, 2 dla info)
// przypisz odpowiednią funkcję do pola notify w notifier
// TODO: Wywołaj powiadomienie za pomocą wskaźnika do funkcji w strukturze
// Użyj: n.notify(message)
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