Poziomy dostępu w dziedziczeniu
Część sekcji Programowanie obiektowe ścieżki C++ w Coddy. Lekcja 49 z 104.
Wybrany typ dziedziczenia wpływa na dostęp do składowych klasy bazowej w klasie pochodnej. C++ oferuje trzy opcje: dziedziczenie public, protected i private.
Oto, jak każdy typ przekształca dostęp do składowych:
| Składowa bazowa | dziedziczenie publiczne | dziedziczenie chronione | dziedziczenie prywatne |
|---|---|---|---|
| public | public | protected | private |
| protected | protected | protected | private |
| private | niedostępne | niedostępne | niedostępne |
class Base {
public:
int pub;
protected:
int prot;
private:
int priv;
};
class PublicDerived : public Base {
// pub jest publiczny, prot jest chroniony, priv jest niedostępny
};
class ProtectedDerived : protected Base {
// pub jest chroniony, prot jest chroniony, priv jest niedostępny
};
class PrivateDerived : private Base {
// pub jest prywatny, prot jest prywatny, priv jest niedostępny
};Dziedziczenie publiczne modeluje relacje „jest-a” i jest zdecydowanie najczęściej stosowanym rodzajem dziedziczenia. Dog to Animal, więc kod zewnętrzny może traktować go jako takie zwierzę.
Dziedziczenie chronione i prywatne modeluje relacje typu „zaimplementowany za pomocą”. Ukrywa interfejs klasy bazowej przed kodem zewnętrznym, co jest przydatne, gdy chcesz ponownie wykorzystać implementację bez ujawniania relacji dziedziczenia. W przypadku dziedziczenia prywatnego nawet klasy pochodne tracą dostęp do oryginalnych składowych klasy bazowej.
Wyzwanie
ŁatwyPrzyjrzyjmy się, jak różne typy dziedziczenia wpływają na dostępność składowych, budując prostą hierarchię urządzeń. Utworzysz bazową klasę Device i trzy klasy pochodne, z których każda będzie używać innego typu dziedziczenia, aby na własne oczy zobaczyć, jak dziedziczenie publiczne, chronione i prywatne zmienia dostęp do składowych.
Rozmieścisz swój kod w dwóch plikach:
Device.h: Zdefiniuj bazową klasęDevicez trzema składowymi o różnych poziomach dostępu:- Publiczna składowa
std::string model - Chroniona składowa
int serialNumber - Prywatna składowa
int internalCode(domyślnie ustawiona na 999) - Publiczna metoda
showModel(), która wypisuje:Model: <model>
Następnie utwórz trzy klasy pochodne, z których każda dziedziczy po
Devicez użyciem innego typu dziedziczenia:PublicDevicez użyciem dziedziczenia publicznego: dodaj metodędisplaySerial(), która wypisuje:Serial: <serialNumber>ProtectedDevicez użyciem dziedziczenia chronionego: dodaj metodędisplaySerial(), która wypisuje:Serial: <serialNumber>PrivateDevicez użyciem dziedziczenia prywatnego: dodaj metodędisplaySerial(), która wypisuje:Serial: <serialNumber>
Każda klasa pochodna powinna mieć konstruktor przyjmujący nazwę modelu i numer seryjny, przekazujący model do klasy bazowej i ustawiający numer seryjny.
- Publiczna składowa
main.cpp: Wczytaj dwa wejścia (każde w osobnym wierszu):- Nazwę modelu (ciąg znaków)
- Numer seryjny (liczba całkowita)
Utwórz po jednym obiekcie każdego typu pochodnego, używając tych samych wartości wejściowych. Następnie pokaż różnice w dostępie:
Dla
PublicDevice:- Wywołaj bezpośrednio na obiekcie
showModel()(działa, ponieważ dziedziczenie publiczne zachowuje publiczny dostęp do tej metody) - Uzyskaj bezpośredni dostęp do
modeli wypisz:Direct model access: <model> - Wywołaj
displaySerial()
Dla
ProtectedDeviceiPrivateDevice:- Wywołaj tylko
displaySerial()(odziedziczoneshowModel()imodelnie są już publicznie dostępne z zewnątrz)
Format wyjściowy:
--- PublicDevice --- Model: <model> Direct model access: <model> Serial: <serial> --- ProtectedDevice --- Serial: <serial> --- PrivateDevice --- Serial: <serial>
Na przykład dla wejść Laptop i 12345:
--- PublicDevice ---
Model: Laptop
Direct model access: Laptop
Serial: 12345
--- ProtectedDevice ---
Serial: 12345
--- PrivateDevice ---
Serial: 12345Zwróć uwagę, że tylko PublicDevice umożliwia zewnętrzny dostęp do odziedziczonych składowych publicznych. Pozostałe typy dziedziczenia ukrywają interfejs klasy bazowej przed kodem zewnętrznym, ale klasy pochodne nadal mogą uzyskiwać wewnętrzny dostęp do składowych chronionych za pośrednictwem własnych metod.
Spróbuj swoich sił
#include <iostream>
#include <string>
#include "Device.h"
using namespace std;
int main() {
// Odczytaj dane wejściowe
string modelName;
int serialNum;
getline(cin, modelName);
cin >> serialNum;
// TODO: Utwórz obiekty każdego typu pochodnego, używając wartości wejściowych
// PublicDevice pubDev(modelName, serialNum);
// ProtectedDevice protDev(modelName, serialNum);
// PrivateDevice privDev(modelName, serialNum);
// TODO: Zademonstruj dostęp do PublicDevice
cout << "--- PublicDevice ---" << endl;
// - Wywołaj showModel() bezpośrednio na obiekcie
// - Uzyskaj bezpośredni dostęp do model i wypisz: Direct model access: <model>
// - Wywołaj displaySerial()
// TODO: Zademonstruj dostęp do ProtectedDevice
cout << "--- ProtectedDevice ---" << endl;
// - Wywołaj tylko displaySerial() (showModel i model nie są publicznie dostępne)
// TODO: Zademonstruj dostęp do PrivateDevice
cout << "--- PrivateDevice ---" << endl;
// - Wywołaj tylko displaySerial() (showModel i model nie są publicznie dostępne)
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