Ukrywanie informacji
Część sekcji Programowanie obiektowe ścieżki C++ w Coddy. Lekcja 36 z 104.
Ukrywanie informacji wykracza poza samo używanie specyfikatorów dostępu. To zasada projektowania, zgodnie z którą ukrywasz nie tylko dane, ale także szczegóły implementacji dotyczące wewnętrznego działania klasy.
Celem jest udostępnienie tylko tego, co użytkownicy Twojej klasy muszą wiedzieć, i ukrycie wszystkiego innego. Dzięki temu możesz zmieniać wewnętrzną implementację bez wpływu na kod korzystający z Twojej klasy:
class Temperature {
double kelvin; // Reprezentacja wewnętrzna – ukryty szczegół
public:
void setCelsius(double c) {
kelvin = c + 273.15; // Konwersja ukryta przed użytkownikiem
}
double getCelsius() const {
return kelvin - 273.15;
}
double getFahrenheit() const {
return (kelvin - 273.15) * 9.0/5.0 + 32;
}
};Użytkownicy tej klasy nie wiedzą (ani nie muszą wiedzieć), że temperatura jest wewnętrznie przechowywana w kelwinach. Jeśli później zdecydujesz się przechowywać ją w stopniach Celsjusza, zmienisz tylko prywatną implementację — publiczny interfejs pozostanie bez zmian.
To oddzielenie interfejsu od implementacji przynosi kilka korzyści: zmniejsza złożoność dla użytkowników Twojej klasy, zapobiega przypadkowemu niewłaściwemu użyciu danych wewnętrznych i ułatwia utrzymanie kodu. Gdy szczegóły wewnętrzne są ukryte, możesz swobodnie optymalizować lub refaktoryzować kod bez psucia istniejącego kodu, który zależy od Twojej klasy.
Wyzwanie
ŁatwyZbudujmy klasę Distance, która demonstruje ukrywanie informacji, przechowując odległości wewnętrznie w centymetrach, a jednocześnie zapewniając przejrzysty interfejs do pracy z różnymi jednostkami. Użytkownicy Twojej klasy nie będą musieli wiedzieć (ani się tym przejmować), w jaki sposób odległość jest przechowywana wewnętrznie: będą po prostu korzystać z najwygodniejszej dla siebie jednostki.
Utworzysz dwa pliki, aby uporządkować swój kod:
Distance.h: Zdefiniuj klasęDistance, która ukrywa swoją wewnętrzną reprezentację, udostępniając jednocześnie elastyczny interfejs publiczny. Wewnątrz przechowuj odległość w centymetrach (jakodouble). To szczegół implementacji, który ma pozostać ukryty. Twój interfejs publiczny powinien umożliwiać użytkownikom:- Ustawianie odległości za pomocą
setMeters(double m),setCentimeters(double cm)lubsetKilometers(double km) - Pobieranie odległości za pomocą
getMeters(),getCentimeters()lubgetKilometers(): wszystkie te metody powinny być metodami const - Dodawanie dwóch odległości za pomocą
add(const Distance& other), która zwraca nowy obiektDistance
Dodaj konstruktor domyślny, który inicjalizuje odległość wartością zero. Logika konwersji powinna być ukryta wewnątrz Twoich metod: użytkownicy po prostu wywołują
setKilometers(5)igetMeters(), nie martwiąc się o wewnętrzny format przechowywania.- Ustawianie odległości za pomocą
main.cpp: Zademonstruj, że użytkownicy mogą korzystać z Twojej klasy bez znajomości jej wewnętrznej reprezentacji. Odczytaj z wejścia dwie wartości odległości: pierwszą w metrach, drugą w kilometrach. Następnie:- Utwórz obiekt
Distancei ustaw jego wartość, korzystając z wartości w metrach - Wypisz
"In meters: <value> m" - Wypisz
"In centimeters: <value> cm" - Wypisz
"In kilometers: <value> km" - Utwórz drugi obiekt
Distancei ustaw jego wartość, korzystając z wartości w kilometrach - Dodaj do siebie obie odległości i zapisz wynik
- Wypisz
"Combined in meters: <value> m"
- Utwórz obiekt
Zaletą ukrywania informacji jest to, że możesz później zmienić wewnętrzny sposób przechowywania odległości z centymetrów na milimetry (lub dowolną inną jednostkę), nie zmieniając sposobu, w jaki użytkownicy korzystają z Twojej klasy. Interfejs publiczny pozostaje stabilny, nawet jeśli implementacja ulegnie zmianie.
Formatuj wszystkie wartości wyjściowe z dwoma miejscami po przecinku, używając std::fixed i std::setprecision(2) z <iomanip>. Konwertuj ciągi wejściowe na wartości typu double za pomocą std::stod().
Przelicznik: 1 metr = 100 centymetrów, 1 kilometr = 1000 metrów.
Spróbuj swoich sił
#include <iostream>
#include <string>
#include <iomanip>
#include "Distance.h"
using namespace std;
int main() {
// Wczytaj wartości wejściowe
string metersInput, kmInput;
cin >> metersInput; // Pierwsza wartość w metrach
cin >> kmInput; // Druga wartość w kilometrach
// Przekonwertuj ciągi znaków na liczby typu double za pomocą std::stod()
double metersValue = stod(metersInput);
double kmValue = stod(kmInput);
// Ustaw formatowanie wyjścia
cout << fixed << setprecision(2);
// TODO: Utwórz pierwszy obiekt Distance i ustaw jego wartość na podstawie wartości w metrach
// TODO: Wypisz "In meters: <value> m"
// TODO: Wypisz "In centimeters: <value> cm"
// TODO: Wypisz "In kilometers: <value> km"
// TODO: Utwórz drugi obiekt Distance i ustaw jego wartość na podstawie wartości w kilometrach
// TODO: Dodaj do siebie obie odległości za pomocą metody add()
// TODO: Wypisz "Combined in meters: <value> m"
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 obiektowego
Pliki zewnętrzneBudowanie i kompilacja C++Pliki nagłówkowe i pliki źródłowePrzestrzenie nazw i zakresWprowadzenie do programowania obiektowego w C++Klasy a obiektyWskaźnik „this”Metody (funkcje składowe)Atrybuty (składowe danych)Podstawy konstruktorów i destruktorówPowtórzenie – prosty kalkulator4Właściwości klas
Elementy instancji a elementy statyczneGettery i setteryStałe funkcje składoweSłowo kluczowe mutableMetody i zmienne statyczneFunkcje i klasy zaprzyjaźnionePodsumowanie – menedżer konta bankowego7Dziedziczenie
Podstawy dziedziczeniaPoziomy dostępu w dziedziczeniuKolejność wywołań konstruktora i destruktoraNadpisywanie metodFunkcje wirtualne i VTableWielokrotne dziedziczenieDziedziczenie wirtualnePowtórzenie — hierarchia pracowników2Zarządzanie pamięcią
Pamięć stosu a stertyWskaźniki i referencjePamięć dynamiczna (new/delete)Inteligentne wskaźniki w C++RAII w C++Podsumowanie — menedżer tablicy dynamicznej5Hermetyzacja
Specyfikatory dostępu w C++Specyfikatory dostępu — szczegółowoUkrywanie informacjiStruktura a klasaKlasy zagnieżdżone i wewnętrznePodsumowanie — system ewidencji studentów8Polimorfizm
Polimorfizm czasu kompilacji i wykonaniaPrzeciążanie funkcjiFunkcje wirtualne — powtórkaCzysto wirtualne funkcjeKlasy abstrakcyjneProjektowanie interfejsów w C++Rzutowanie dynamiczne i RTTIPodsumowanie — kalkulator kształtów3Konstruktory i destruktory
Konstruktor domyślnyKonstruktor z parametramiKonstruktor kopiującyKonstruktor przenoszącyListy inicjalizacyjne konstruktoraKonstruktory delegująceDestruktor — szczegółowe omówienieZasada trzech / pięciu / zeraPodsumowanie — klasa String6Przeciążanie operatorów
Wprowadzenie do przeciążania operatorówPrzeciążanie operatorów arytmetycznychPrzeciążanie operatorów porównaniaOperatory strumieniowePrzeciążanie operatora przypisaniaPrzeciążanie operatorów [] i ()Operatory konwersji typówPodsumowanie — klasa Matrix9Szablony
Szablony funkcjiSzablony klasSpecjalizacja szablonówSzablony wariadycznePodstawy SFINAE i cech typówPodsumowanie — kontener generycznyPoćwicz samodzielnie: Kompilator C++ online