Poprawność const
Część sekcji Programowanie obiektowe ścieżki C w Coddy. Lekcja 8 z 61.
Podczas pisania funkcji działających jak metody niektóre powinny modyfikować obiekt (tak jak player_take_damage), a inne powinny jedynie odczytywać dane, niczego nie zmieniając. Słowo kluczowe const pozwala wymusić to rozróżnienie na poziomie kompilatora.
Oznaczając parametr wskaźnikowy jako const, obiecujesz, że funkcja nie zmodyfikuje wskazywanych przez niego danych. Jeśli przypadkowo spróbujesz zmienić składową, kompilator zgłosi błąd:
typedef struct {
int x;
int y;
} Point;
// Ta funkcja może tylko ODCZYTYWAĆ punkt
void point_print(const Point *self) {
printf("(%d, %d)\n", self->x, self->y);
// self->x = 10; // BŁĄD: nie można modyfikować przez wskaźnik const
}
// Ta funkcja może MODYFIKOWAĆ punkt
void point_move(Point *self, int dx, int dy) {
self->x += dx;
self->y += dy;
}
Parametr const Point *self informuje kompilator i innych programistów, że point_print jest „funkcją pobierającą” lub operacją tylko do odczytu. Nazywa się to poprawnością const: używaniem const wszędzie tam, gdzie modyfikacja nie jest potrzebna.
Ta praktyka pozwala wcześnie wykrywać błędy. Jeśli napiszesz funkcję wyświetlającą i przypadkowo zmodyfikujesz pole, kompilator natychmiast Cię zatrzyma, zamiast pozwolić, by błąd przedostał się do Twojego programu.
Wyzwanie
ŁatwyZbudujmy moduł Temperature, który przechowuje wartość temperatury i udostępnia operacje tylko do odczytu oraz modyfikujące. Dzięki temu przećwiczysz używanie wskaźników const, aby wyraźnie odróżniać funkcje, które tylko odczytują dane, od tych, które je zmieniają.
Utworzysz trzy pliki:
temperature.h: Zadeklaruj strukturęTemperaturez jednym polemdouble celsius. Zadeklaruj też trzy funkcje:temp_display: przyjmuje wskaźnikconstdo Temperature i wyświetla bieżącą temperaturę (tylko do odczytu)temp_adjust: przyjmuje zwykły wskaźnik do Temperature oraz wartość typu double, a następnie dodaje tę wartość do celsius (modyfikowanie)temp_to_fahrenheit: przyjmuje wskaźnikconstdo Temperature i zwraca wartość przeliczoną na stopnie Fahrenheita (tylko do odczytu)
TEMPERATURE_H.temperature.c: Zaimplementuj wszystkie trzy funkcje. Funkcjatemp_displaypowinna wyświetlać wynik w formacieCurrent: {celsius}C. Funkcjatemp_to_fahrenheitpowinna zwracaćcelsius * 9.0 / 5.0 + 32.0. Pamiętaj, że funkcje używające wskaźnikówconstnie mogą modyfikować danych struktury.main.c: Utwórz obiekt Temperature, wykonaj operacje i wyświetl wyniki.
Otrzymasz dwa wejścia: początkową wartość w stopniach Celsjusza (typu double) oraz wartość korekty (typu double).
W pliku main:
- Zainicjuj obiekt
Temperaturepoczątkową wartością w stopniach Celsjusza - Wywołaj
temp_display, aby wyświetlić temperaturę początkową - Wywołaj
temp_adjust, aby zmienić temperaturę o wartość korekty - Ponownie wywołaj
temp_display, aby wyświetlić zaktualizowaną temperaturę - Wyświetl temperaturę w stopniach Fahrenheita, używając
temp_to_fahrenheit
Wyświetl wyniki w tym formacie:
Current: {celsius}C
Current: {celsius}C
Fahrenheit: {fahrenheit}FUżyj %.1f dla wszystkich wartości temperatury, aby wyświetlić jedno miejsce po przecinku.
Na przykład dla wartości początkowej 20.0 i korekty 5.0 wynik będzie następujący:
Current: 20.0C
Current: 25.0C
Fahrenheit: 77.0FSpróbuj swoich sił
#include <stdio.h>
#include "temperature.h"
int main() {
double initial_celsius, adjustment;
scanf("%lf", &initial_celsius);
scanf("%lf", &adjustment);
// TODO: Utwórz strukturę Temperature i zainicjalizuj ją wartością initial_celsius
// TODO: Wywołaj temp_display, aby wyświetlić temperaturę początkową
// TODO: Wywołaj temp_adjust, aby zmienić temperaturę o wartość adjustment
// TODO: Ponownie wywołaj temp_display, aby wyświetlić zaktualizowaną temperaturę
// TODO: Wyświetl temperaturę w stopniach Fahrenheita za pomocą temp_to_fahrenheit
// Format: "Fahrenheit: %.1fF\n"
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