inheritance c
Znaczenie dziedziczenia w C ++ z przykładami:
Dziedziczenie jest jedną z najważniejszych cech programowania obiektowego.
Dziedziczenie to technika, za pomocą której jedna klasa uzyskuje właściwości i metody innej klasy. W ten sposób możemy ponownie wykorzystać kod, który jest już napisany i zweryfikowany. Klasa, która uzyskuje właściwości innej klasy, nazywana jest podklasą, klasą pochodną lub klasą potomną.
Klasa, której właściwości są nabywane, nazywana jest klasą bazową, klasą nadrzędną lub nadklasą. Kiedy jedna klasa nabywa lub dziedziczy inną klasę, wówczas wszystkie właściwości i metody klasy bazowej są dostępne dla klasy pochodnej, dzięki czemu możemy ponownie użyć tego kodu.
=> Odwiedź tutaj, aby nauczyć się C ++ od podstaw.
dobry downloader muzyki mp3 dla Androida
Czego się nauczysz:
- Dlaczego potrzebujemy dziedziczenia?
- Tryby dziedziczenia
- Kolejność konstruktorów / niszczycieli w dziedziczeniu
- Rodzaje dziedziczenia
- Dziedziczenie szablonów
- Kompozycja
- Jak powinniśmy wybrać między składem a dziedziczeniem?
- Wniosek
- rekomendowane lektury
Dlaczego potrzebujemy dziedziczenia?
Rozważ grupę pojazdów, takich jak samochód, autobus, jeep itp. Każdy z tych pojazdów będzie miał właściwości i metody, jak pokazano na poniższym schemacie.
Jeśli będziemy musieli zaimplementować poszczególne klasy dla powyższych pojazdów, widzimy, że we wszystkich trzech klasach będziemy musieli napisać ten sam kod, ponieważ wszystkie trzy typy pojazdów będą mniej lub bardziej wykazywać te same właściwości. To sprawi, że nasz program będzie nieefektywny i uciążliwy, ponieważ będzie dużo zduplikowanych kodów.
Zamiast pisać zduplikowany kod, jak powyżej, możemy zaimplementować funkcję dziedziczenia, aby zapobiec powielaniu się kodu, a także napisać pojedynczy fragment kodu i używać go we wszystkich trzech klasach. Jest to obrazowo przedstawione poniżej.
Na powyższym rysunku zdefiniowaliśmy klasę bazową „Pojazdy” i wyprowadziliśmy z tej klasy klasy Samochód, Autobus i Jeep. Powszechne metody i właściwości są teraz częścią klasy Pojazdy. Ponieważ inne klasy wywodzą się z klasy Pojazdy, wszystkie klasy uzyskują te metody i właściwości.
W związku z tym wystarczy napisać wspólny kod tylko raz i wszystkie trzy klasy; Kupią go samochód, autobus i jeep.
Zatem główną zaletą, jaką uzyskujemy poprzez dziedziczenie istniejących klas lub projektowanie mechanizmu dziedziczenia, jest możliwość ponownego wykorzystania kodu.
Dalsza lektura = >> Samouczek dotyczący dziedziczenia w języku Java
Ogólny format dziedziczenia klas to:
class derived_classname: access_specifier base_classname { };
Tutaj “ nazwa_klasy_ pochodnej ”To nazwa klasy pochodnej,„ access_specifier ”To tryb dostępu, tj. Publiczny, chroniony lub prywatny, w którym klasa pochodna musi odziedziczyć klasę bazową, a„ nazwa_klasy_ pochodnej ”To nazwa klasy bazowej, z której dziedziczy klasa pochodna.
Tryby dziedziczenia
„Access_specifier” pokazany w powyższej deklaracji dziedziczenia może mieć swoje wartości, jak pokazano poniżej.
W zależności od parametru access_specifier określonego podczas dziedziczenia klasy, mamy różne tryby dziedziczenia wymienione poniżej.
Dziedziczenie publiczne
Ogólna składnia
class sub_class : public parent_class
Gdy określono specyfikator dostępu publicznego, publiczne elementy członkowskie klasy bazowej są dziedziczone jako publiczne, podczas gdy chronione elementy członkowskie są chronione. Członkowie prywatni pozostają prywatni. To najpopularniejszy sposób dziedziczenia.
Dziedziczenie prywatne
Ogólna składnia
class sub_class : parent_class
Dziedziczenie prywatne niczego nie dziedziczy. Gdy używany jest specyfikator dostępu prywatnego, publiczne i chronione elementy członkowskie klasy bazowej również stają się prywatne.
Dziedziczenie chronione
Ogólna składnia
class sub_class:protected parent_class
Gdy używany jest specyfikator dostępu chronionego, publiczne i chronione elementy członkowskie klasy bazowej stają się chronionymi elementami członkowskimi w klasie pochodnej.
Zauważ, że kiedy używamy specyfikatora dostępu prywatnego dla klasy bazowej, żaden z elementów klasy bazowej nie jest dziedziczony. Wszystkie stają się prywatne w klasie pochodnej.
Poniżej podano tabelaryczną reprezentację wszystkich trybów dostępu i ich interpretację w celu dziedziczenia.
Klasa pochodna -> Klasa podstawowa | Prywatny | Publiczny | Chroniony |
---|---|---|---|
Prywatny | Nie dziedziczone | Nie dziedziczone | Nie dziedziczone |
Publiczny | Prywatny | Publiczny | Chroniony |
Chroniony | Prywatny | Chroniony | Chroniony |
Kolejność konstruktorów / niszczycieli w dziedziczeniu
Gdy klasy są dziedziczone, konstruktory są wywoływane w tej samej kolejności, w jakiej są dziedziczone. Jeśli mamy klasę bazową i jedną klasę pochodną, która dziedziczy tę klasę bazową, najpierw zostanie wywołany konstruktor klasy bazowej (domyślny lub sparametryzowany), a po nim konstruktor klasy pochodnej.
Poniższy program demonstruje kolejność konstruktorów w dziedziczeniu. Mamy klasę bazową „Base”, która ma domyślny konstruktor i sparametryzowany konstruktor. Wyprowadzamy z tego klasę o nazwie „Derived”, która ma również jeden domyślny i inny sparametryzowany konstruktor.
Dane wyjściowe tego programu pokazują kolejność, w jakiej konstruktory są wywoływane.
najlepsze darmowe narzędzie do naprawy systemu Windows 7
#include using namespace std; //order of execution of constructors in inheritance class Base { int x; public: // default constructor Base() { cout Wynik:
Domyślny konstruktor klasy bazowej
Domyślny konstruktor klasy bazowej
Domyślny konstruktor klasy pochodnej
Konstruktor sparametryzowany klasy bazowej
Konstruktor sparametryzowany klasy pochodnej
Widzimy, że po utworzeniu obiektu klasy bazowej tworzymy obiekt klasy pochodnej z domyślnym konstruktorem. Po utworzeniu tego obiektu najpierw wywoływany jest domyślny konstruktor klasy bazowej, a następnie wykonywany jest konstruktor klasy pochodnej.
Podobnie, gdy obiekt klasy pochodnej jest tworzony przy użyciu sparametryzowanego konstruktora, najpierw wywoływany jest sparametryzowany konstruktor klasy bazowej, a następnie konstruktor klasy pochodnej.
Należy zauważyć, że gdyby w klasie bazowej nie było sparametryzowanego konstruktora, wówczas domyślny konstruktor zostałby wywołany nawet w celu skonstruowania sparametryzowanego obiektu klasy pochodnej.
Pozostaje jednak pytanie, dlaczego konstruktor klasy bazowej jest wywoływany podczas konstruowania obiektów klasy pochodnej?
Wiemy, że konstruktor jest używany do tworzenia obiektów klasy, a także do inicjowania jej członków. Gdy tworzony jest obiekt klasy pochodnej, jego konstruktor ma kontrolę tylko nad składowymi klasy pochodnej.
Jednak klasa pochodna dziedziczy również elementy członkowskie klasy bazowej. Gdyby został wywołany tylko konstruktor klasy pochodnej, elementy członkowskie klasy podstawowej odziedziczone przez klasę pochodną nie zostałyby poprawnie zainicjowane.
W rezultacie cały obiekt nie zostanie utworzony wydajnie. Z tego powodu wszystkie konstruktory klasy bazowej są wywoływane jako pierwsze podczas tworzenia obiektu klasy pochodnej.
Rodzaje dziedziczenia
W zależności od sposobu, w jaki klasa jest wyprowadzana lub ile klas podstawowych dziedziczy klasa, mamy następujące typy dziedziczenia, jak pokazano na poniższym rysunku.

Zbadamy każdy z tych typów w następnym samouczku „Typy dziedziczenia”.
Dziedziczenie szablonów
Kiedy nasza implementacja obejmuje szablony, musimy dziedziczyć lub wyprowadzać z klas szablonów i używamy tam dziedziczenia szablonów.
Przejdźmy bezpośrednio do przykładu programowania, aby lepiej zrozumieć dziedziczenie przy użyciu szablonów.
#include using namespace std; //template inhertance templateclass basecls_Template { public: T value; basecls_Template(T value) { this->value = value; } void displayVal() { cout << value << endl; } }; //derived class inherits basecls_Template class derivedcls_Child : public basecls_Template { public: derivedcls_Child(/* no parameters */): basecls_Template( 0 ){ // default char is NULL; } derivedcls_Child(char c): basecls_Template( c ) { ; } void displayVal_drvd() { displayVal(); } }; int main() { basecls_Template obj( 100 ); derivedcls_Child obj1( 'A' ); cout<<'basecls_Template obj = '; obj.displayVal(); // should print '100' cout< Wynik:
basecls_Template obj = 100
pochodnecls_Child obj1 (dziedziczone z basecls_Template = A
W powyższym programie mamy szablon o nazwie basecls_Template, który definiuje szablon klasy dla klasy bazowej. Następnie definiujemy klasę pochodnącls_Child, którą chcemy wyprowadzić z klasy szablonu.
Należy jednak pamiętać, że klasa basecls_Template jest tylko typem, a nie klasą. W związku z tym nie możemy wyprowadzić klasy pochodnejcls_Child z tego szablonu.
Dlatego jeśli zadeklarujemy klasę potomną jako:
class derivedcls_Child : public basecls_Template
Spowoduje to błąd. Powodem tego, że basecls_Template jest typ danych, a nie klasa. Tak więc, aby dziedziczyć składowe basecls_Template, powinniśmy najpierw utworzyć jego egzemplarz, zanim zaczniemy z niego wywodzić.
Dlatego powyższe stwierdzenie, Klasa pochodnacls_Child: public basecls_Template działa w porządku.
W tej instrukcji utworzyliśmy instancję szablonu basecls_Template do szablonu klasy znaków. Kiedy już użyjemy tej instancji klasy szablonu, wtedy pozostałe rzeczy, takie jak tworzenie i używanie obiektów, zbiegają się ze zwykłym działaniem dziedziczenia.
Kompozycja
Do tej pory widzieliśmy wszystko o związkach dziedziczenia. Dziedziczenie zasadniczo opisuje rodzaj relacji, w których relacja wskazuje część. Na przykład, Wąż to rodzaj gada. Możemy również powiedzieć, że gad jest częścią klasy zwierząt.
Podsumowując, dziedziczenie wskazuje 'JEST' rodzaj relacji, w których możemy powiedzieć, że klasa pochodna jest częścią klasy bazowej.
Możemy również przedstawiać relacje jako całość. Na przykład, jeśli powiemy, że klasa wynagrodzenia jest częścią klasy pracownika, to nie reprezentujemy jej właściwie. Wiemy, że Pracownicy mają wynagrodzenie. Dlatego wygodniej jest powiedzieć: „Pracownik ma wynagrodzenie”.
Podobnie, jeśli weźmiemy na przykład klasę Pojazdy, możemy powiedzieć, że pojazd ma silnik lub pojazd ma podwozie. W ten sposób przedstawiają wszystkie te relacje 'MA' relacje, które reprezentują cały obiekt zawarty w innej klasie. Jest to zdefiniowane jako Kompozycja .
Relacje przedstawione przez kompozycję są od siebie zależne. Na przykład, Podwozie nie może istnieć bez pojazdu. Podobnie, wynagrodzenie nie może istnieć bez pracownika.
Możemy schematycznie przedstawić skład, jak pokazano poniżej:

Kompozycja jest również nazywana ograniczeniem. W powyższej reprezentacji pokazaliśmy klasę nadrzędną. W przeciwieństwie do dziedziczenia, umieszczamy obiekt klasy potomnej w klasie nadrzędnej. To jest ograniczenie lub kompozycja.
Aby to zrozumieć, weźmy przykład programowania.
c ++ konwertowanie char na int
#include using namespace std; //Composition example //Child class - address class Address { public: string houseNo, building, street, city, state; //Initialise the address object Address(string houseNo,string building,string street, string city, string state) { this->houseNo = houseNo; this->building = building; this->street = street; this->city = city; this->state = state; } }; //Parent class - Employee class Employee { private: Address* address; //composition->Employee has an address public: int empId; string empName; Employee(int empId, string empName, Address* address) { this->empId = empId; this->empName = empName; this->address = address; } void display() { cout< Wynik:
10001 Ved
A-101 Silver Springs Aundh Pune Maharashtra
W tym przykładzie mamy klasę nadrzędną Employee i adres klasy podrzędnej. Wewnątrz klasy nadrzędnej Employee zadeklarowaliśmy wskaźnik do klasy Address, a także zainicjowaliśmy ten obiekt w konstruktorze Employee. W ten sposób przedstawiamy relację, w której pracownik ma adres, który jest składem.
Jak powinniśmy wybrać między składem a dziedziczeniem?
Skład i dziedziczenie przedstawiają relacje między klasami. Podczas gdy dziedziczenie przedstawia zależność „IS-A”, kompozycja przedstawia zależność „HAS-A”.
Teraz pytanie brzmi, kiedy powinniśmy używać dziedziczenia, a kiedy kompozycji? W rzeczywistości nie możemy decydować o konkretnych sytuacjach, kiedy powinniśmy użyć któregokolwiek z nich. Dzieje się tak, ponieważ każdy ma swoje zalety i wady.
Oba promują możliwość ponownego wykorzystania kodu. Dziedziczenie może spowodować, że kod będzie nieporęczny, ponieważ rozwiązania stają się złożone, ale jednocześnie pozwala nam również rozszerzyć istniejący kod. Dlatego powinniśmy używać dziedziczenia, gdy naszym wymaganiem jest zmodyfikowanie i użycie właściwości i metody innej klasy wewnątrz nowej klasy.
Innymi słowy, gdy chcemy dodać więcej właściwości i rozszerzyć istniejącą klasę. Z drugiej strony, gdy nie chcemy modyfikować właściwości i zachowania innej klasy, ale po prostu używamy jej wewnątrz klasy, wybieramy kompozycję.
Zatem najlepszą decyzję, czy zastosować kompozycję, czy dziedziczenie, podejmie się rozważając zalety i wady obu technik w danej sytuacji.
= >> Przeczytaj także artykuł Kompozycja w Javie
Wniosek
W ten sposób dotarliśmy do końca naszego tematu dotyczącego dziedziczenia. Widzieliśmy różne sposoby dziedziczenia. Widzieliśmy również typy dziedziczenia, które omówimy w następnym samouczku. Dowiedzieliśmy się o kolejności konstruktorów, które są wykonywane w przypadku dziedziczenia.
Przestudiowaliśmy również szablony i dziedziczenie. Musimy utworzyć instancję szablonu, zanim będziemy mogli go użyć w dziedziczeniu, ponieważ sam szablon jest typem danych i nie możemy dziedziczyć z typu danych.
Kompozycja jest innym rodzajem relacji klasowej i najpierw musimy poznać dokładną sytuację, a dopiero potem możemy zdecydować, czy użyć kompozycji, czy dziedziczenia.
W naszym nadchodzącym samouczku dowiemy się więcej o typach dziedziczenia.
=> Obejrzyj serię prostych szkoleń C ++ tutaj.
rekomendowane lektury
- Rodzaje dziedziczenia w C ++
- Polimorfizm środowiska uruchomieniowego w C ++
- Funkcje znajomego w C ++
- Wykorzystanie klasy Selenium Select do obsługi elementów rozwijanych na stronie internetowej - Samouczek Selenium nr 13
- Klasy i obiekty w C ++
- Statyczny w C ++
- Samouczek dotyczący potoków w systemie Unix: Potoki w programowaniu w systemie Unix
- Interfejs Java i samouczek klasy abstrakcyjnej z przykładami