Condividi tramite


Classi astratte (C++)

Le classi astratte fungono da espressioni di concetti generali da cui è possibile derivare classi più specifiche. Non è possibile creare un oggetto di un tipo di classe astratta. Tuttavia, è possibile usare puntatori e riferimenti ai tipi di classe astratti.

Si crea una classe astratta dichiarando almeno una funzione membro virtuale pura. Si tratta di una funzione virtuale dichiarata usando la sintassi dell'identificatore puro (= 0). Le classi derivate dalla classe astratta devono implementare la funzione virtuale pura o sono anch'esse classi astratte.

Si consideri l'esempio presentato in Funzioni virtuali. Lo scopo della classe Account è di fornire la funzionalità generale, ma gli oggetti di tipo Account sono troppo generici per essere utili. Ciò significa Account che è un buon candidato per una classe astratta:

// 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;
};

L'unica differenza tra questa dichiarazione e la precedente è che PrintBalance è dichiarato con l'identificatore pure (= 0).

Limitazioni alle classi astratte

Le classi astratte non possono essere usate per:

  • Variabili o dati dei membri

  • Tipi di argomento

  • Tipi restituiti di funzione

  • Tipi di conversioni esplicite

Se il costruttore per una classe astratta chiama una funzione virtuale pura, direttamente o indirettamente, il risultato non è definito. Tuttavia, i costruttori e i distruttori per le classi astratte possono chiamare altre funzioni membro.

Funzioni virtuali pure definite

Le funzioni virtuali pure nelle classi astratte possono essere definite o hanno un'implementazione. È possibile chiamare tali funzioni solo usando la sintassi completa:

abstract-class-name::function-name()

Le funzioni virtuali pure definite sono utili quando si progettano gerarchie di classi le cui classi di base includono distruttori virtuali puri. Ciò è dovuto al fatto che i distruttori della classe base vengono sempre chiamati durante la distruzione degli oggetti. Si consideri l'esempio seguente:

// 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
}

L'esempio mostra come un'estensione del compilatore Microsoft consente di aggiungere una definizione inline a un oggetto virtuale ~base()puro. È anche possibile definirlo all'esterno della classe usando base::~base() {}.

Quando l'oggetto aDerived esce dall'ambito, viene chiamato il distruttore per la classe derived . Il compilatore genera codice per chiamare in modo implicito il distruttore per la classe base dopo il derived distruttore. L'implementazione vuota per la funzione ~base virtuale pura garantisce che per la funzione esista almeno un'implementazione. Senza di esso, il linker genera un errore di simbolo esterno non risolto per la chiamata implicita.

Nota

Nell'esempio precedente, la funzione virtuale pure base::~base viene chiamata in modo implicito da derived::~derived. È anche possibile chiamare in modo esplicito funzioni virtuali pure usando un nome completo di funzione membro. Tali funzioni devono avere un'implementazione o la chiamata genera un errore in fase di collegamento.

Vedi anche

Ereditarietà