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ż

Dziedziczenie