Klasy abstrakcyjne (C++)
Klasy abstrakcyjne działają jako wyrażenia ogólnych pojęć, z których można uzyskać bardziej szczegółowe klasy. Nie można utworzyć obiektu typu klasy abstrakcyjnej. Można jednak użyć wskaźników i odwołań do typów klas abstrakcyjnych.
Klasę abstrakcyjną można utworzyć, deklarując co najmniej jedną czystą wirtualną funkcję składową. Jest to funkcja wirtualna zadeklarowana przy użyciu czystej składni specyfikatora (= 0
). Klasy pochodzące z klasy abstrakcyjnej muszą implementować czystą funkcję wirtualną lub też są klasy abstrakcyjne.
Rozważmy przykład przedstawiony w obszarze Funkcje wirtualne. Intencją klasy Account
jest zapewnienie ogólnej funkcjonalności, ale obiekty typu Account
są zbyt ogólne, aby być przydatne. Oznacza to Account
, że jest dobrym kandydatem do klasy abstrakcyjnej:
// deriv_AbstractClasses.cpp
// compile with: /LD
class Account {
public:
Account( double d ); // Constructor.
virtual double GetBalance(); // Obtain balance.
virtual void PrintBalance() = 0; // Pure virtual function.
private:
double _balance;
};
Jedyną różnicą między tą deklaracją a poprzednią jest PrintBalance
zadeklarowana z czystym specyfikatorem (= 0
).
Ograniczenia dotyczące klas abstrakcyjnych
Klasy abstrakcyjne nie mogą być używane dla:
Zmienne lub dane składowe
Typy argumentów
Typy zwracane przez funkcję
Typy jawnych konwersji
Jeśli konstruktor klasy abstrakcyjnej wywołuje czystą funkcję wirtualną, bezpośrednio lub pośrednio, wynik jest niezdefiniowany. Jednak konstruktory i destruktory dla klas abstrakcyjnych mogą wywoływać inne funkcje składowe.
Zdefiniowane czyste funkcje wirtualne
Czyste funkcje wirtualne w klasach abstrakcyjnych można zdefiniować lub mieć implementację. Takie funkcje można wywoływać tylko przy użyciu w pełni kwalifikowanej składni:
abstract-class-name::function-name()
Zdefiniowane czyste funkcje wirtualne są przydatne podczas projektowania hierarchii klas, których klasy bazowe obejmują czyste destruktory wirtualne. Dzieje się tak, ponieważ destruktory klas bazowych są zawsze wywoływane podczas niszczenia obiektów. Rozważmy następujący przykład:
// deriv_RestrictionsOnUsingAbstractClasses.cpp
// Declare an abstract base class with a pure virtual destructor.
// It's the simplest possible abstract class.
class base
{
public:
base() {}
// To define the virtual destructor outside the class:
virtual ~base() = 0;
// Microsoft-specific extension to define it inline:
// virtual ~base() = 0 {};
};
base::~base() {} // required if not using Microsoft extension
class derived : public base
{
public:
derived() {}
~derived() {}
};
int main()
{
derived aDerived; // destructor called when it goes out of scope
}
W przykładzie pokazano, jak rozszerzenie kompilatora firmy Microsoft umożliwia dodanie definicji wbudowanej do czystej wirtualnej .~base()
Można go również zdefiniować poza klasą przy użyciu polecenia base::~base() {}
.
Gdy obiekt aDerived
wykracza poza zakres, wywoływany jest destruktor klasy derived
. Kompilator generuje kod w celu niejawnego wywołania destruktora klasy base
po destruktorze derived
. Pusta implementacja czystej funkcji ~base
wirtualnej gwarantuje, że dla funkcji istnieje co najmniej pewna implementacja. Bez niego konsolidator generuje nierozwiązany błąd symbolu zewnętrznego dla wywołania niejawnego.
Uwaga
W poprzednim przykładzie czysta funkcja base::~base
wirtualna jest wywoływana niejawnie z derived::~derived
. Istnieje również możliwość jawnego wywołania czystych funkcji wirtualnych przy użyciu w pełni kwalifikowanej nazwy funkcji składowej. Takie funkcje muszą mieć implementację lub wywołanie powoduje błąd w czasie połączenia.
Zobacz też
Opinia
https://aka.ms/ContentUserFeedback.
Dostępne już wkrótce: W 2024 r. będziemy stopniowo wycofywać zgłoszenia z serwisu GitHub jako mechanizm przesyłania opinii na temat zawartości i zastępować go nowym systemem opinii. Aby uzyskać więcej informacji, sprawdź:Prześlij i wyświetl opinię dla