Udostępnij za pośrednictwem


Pojedyncze dziedziczenie

W "pojedynczym dziedziczeniu" - powszechnej formie dziedziczenia - klasy mają tylko jedną klasę podstawową.Należy rozważyć relację zilustrowaną na poniższym rysunku.

Wykres prostego pojedynczego dziedziczenia

Wykres dziedziczenia pojedynczym podstawowe

Zauważ przejście od ogólności do szczegółów na rysunku.Innym typowym atrybutem odnajdowanym w projektach większości hierarchii klas jest to, że klasa pochodna posiada relację "rodzaju" z klasą podstawową.Na rysunku Book jest rodzajem PrintedDocument, a PaperbackBook jest rodzajem book.

Jeden z innych elementów uwagi na rysunku: Book jest zarówno klasą pochodną (od PrintedDocument) i klasą podstawową (PaperbackBook pochodzi od Book).W poniższym przykładzie pokazano szkieletową deklarację takiej hierarchii klas:

// deriv_SingleInheritance.cpp
// compile with: /LD
class PrintedDocument {};

// Book is derived from PrintedDocument.
class Book : public PrintedDocument {};

// PaperbackBook is derived from Book.
class PaperbackBook : public Book {};

PrintedDocument uznaje się za "bezpośrednią bazę" klasy dla Book; jest ona "pośrednią bazą" dla PaperbackBook.Różnica polega na tym, że bezpośrednia klasa podstawowa pojawia się na liście baz deklaracji klasy, a baza pośrednia nie.

Klasa podstawowa, od której pochodzi każda klasa, zadeklarowana jest przed deklaracją klasy pochodnej.Nie wystarczy podanie deklaracji odwołania w przód dla klasy podstawowej; musi ona być pełną deklaracją.

W poprzednim przykładzie użyto specyfikatora dostępu public.Znaczenie publicznego, chronionego i prywatnego dziedziczenia jest opisane w Kontrola dostępu do elementów członkowskich.

Klasa może służyć jako klasa podstawowa dla wielu określonych klas, jak przedstawiono na poniższym rysunku.

Przykład acyklicznego grafu skierowanego

Przekierowanie acykliczne wykresu

Na pokazanym powyżej diagramie o nazwie "acykliczny graf skierowany" (lub "DAG"), niektóre klasy są klasami podstawowymi dla więcej niż jednej klasy pochodnej.Jednakże odwrotna sytuacja nie zachodzi; istnieje tylko jedna bezpośrednia klasa podstawowa dla dowolnej klasy pochodnej.Graf na rysunku przedstawia strukturę "pojedynczego dziedziczenia".

[!UWAGA]

Acykliczne grafy skierowane nie są unikatowe dla pojedynczego dziedziczenia.Są one również wykorzystywane do zobrazowania grafów wielokrotnego dziedziczenia.Temat ten omówiono w Wielokrotne dziedziczenie.

W dziedziczeniu klasa pochodna zawiera elementy członkowskie klasy podstawowej oraz wszelkie dodane nowe elementy członkowskie.W rezultacie klasa pochodna może odwołać się do elementów członkowskich klasy podstawowej (chyba że te elementy członkowskie są ponownie zdefiniowane w klasie pochodnej).Operator rozwiązania zakresu (::) może służyć do odwoływania się do elementów członkowskich bezpośrednich lub pośrednich klas podstawowych, gdy te elementy członkowskie zostały ponownie zdefiniowane w klasie pochodnej.Rozważmy następujący przykład:

// deriv_SingleInheritance2.cpp
// compile with: /EHsc /c
#include <iostream>
using namespace std;
class Document {
public:
   char *Name;   // Document name.
   void PrintNameOf();   // Print name.
};

// Implementation of PrintNameOf function from class Document.
void Document::PrintNameOf() {
   cout << Name << endl;
}

class Book : public Document {
public:
   Book( char *name, long pagecount );
private:
   long  PageCount;
};

// Constructor from class Book.
Book::Book( char *name, long pagecount ) {
   Name = new char[ strlen( name ) + 1 ];
   strcpy_s( Name, strlen(Name), name );
   PageCount = pagecount;
};

Należy zauważyć, że konstruktor dla Book, (Book::Book) posiada dostęp do elementu członkowskiego danych Name.W programie, obiekt typu Book może być utworzony i używany w następujący sposób:

//  Create a new object of type Book. This invokes the
//   constructor Book::Book.
Book LibraryBook( "Programming Windows, 2nd Ed", 944 );

...

//  Use PrintNameOf function inherited from class Document.
LibraryBook.PrintNameOf();

Jak pokazano w powyższym przykładzie, element członkowski klasy i dziedziczone dane oraz funkcje są używane w ten sam sposób.Jeśli implementacja dla klasy Book wywołuje ponowną implementację funkcji PrintNameOf, funkcja należąca do klasy Document może być wywołana jedynie przy pomocy operatora rozwiązania zakresu (::):

// deriv_SingleInheritance3.cpp
// compile with: /EHsc /LD
#include <iostream>
using namespace std;

class Document {
public:
   char *Name;          // Document name.
   void  PrintNameOf() {}  // Print name.
};

class Book : public Document {
   Book( char *name, long pagecount );
   void PrintNameOf();
   long  PageCount;
};

void Book::PrintNameOf() {
   cout << "Name of book: ";
   Document::PrintNameOf();
}

Wskaźniki i odwołania do klas pochodnych mogą być niejawnie konwertowane na wskaźniki i odwołania do ich klas podstawowych, jeśli istnieje dostępna, jednoznaczna klasa podstawowa.W poniższym kodzie pokazano tą koncepcję z użyciem wskaźników (taką samą zasadę stosuje się do odwołań):

// deriv_SingleInheritance4.cpp
// compile with: /W3
struct Document {
   char *Name;
   void PrintNameOf() {}
};

class PaperbackBook : public Document {};

int main() {
   Document * DocLib[10];   // Library of ten documents.
   for (int i = 0 ; i < 10 ; i++)
      DocLib[i] = new Document;
}

W powyższym przykładzie tworzone są różne typy.Jednak ponieważ te typy pochodzą od klasy Document, występuje niejawna konwersja do Document *.W rezultacie DocLib jest "listą heterogeniczną" (lista, na której nie wszystkie obiekty są tego samego typu) zawierającą różne rodzaje obiektów.

Ponieważ klasa Document posiada funkcję PrintNameOf, może wydrukować nazwę każdej książki w bibliotece, choć może pominąć niektóre informacje specyficzne dla typu dokumentu (liczbę stron dla Book, liczbę bajtów dla HelpFile, itd.).

[!UWAGA]

Wymuszanie zaimplementowania funkcji takiej jak PrintNameOf w klasie podstawowej często nie jest najlepszym rozwiązaniem projektowym.Funkcje wirtualne oferują inne alternatywy projektowe.

Zobacz też

Informacje

Przegląd klas pochodnych

Dziedziczenie wielokrotne