Interfacce in C ++ (classi astratte)

Un'interfaccia descrive il comportamento o le capacità di una classe C ++ senza impegnarsi in una particolare implementazione di quella classe.

Le interfacce C ++ vengono implementate utilizzando abstract classes e queste classi astratte non devono essere confuse con l'astrazione dei dati che è un concetto per mantenere i dettagli di implementazione separati dai dati associati.

Una classe viene resa astratta dichiarando almeno una delle sue funzioni come pure virtualfunzione. Una funzione virtuale pura viene specificata inserendo "= 0" nella sua dichiarazione come segue:

class Box {
   public:
      // pure virtual function
      virtual double getVolume() = 0;
      
   private:
      double length;      // Length of a box
      double breadth;     // Breadth of a box
      double height;      // Height of a box
};

Lo scopo di un file abstract class(spesso indicato come ABC) è quello di fornire una classe base appropriata da cui possono ereditare altre classi. Le classi astratte non possono essere utilizzate per istanziare oggetti e servono solo come fileinterface. Il tentativo di istanziare un oggetto di una classe astratta causa un errore di compilazione.

Quindi, se una sottoclasse di un ABC deve essere istanziato, deve implementare ciascuna delle funzioni virtuali, il che significa che supporta l'interfaccia dichiarata dall'ABC. L'impossibilità di sovrascrivere una funzione virtuale pura in una classe derivata, quindi il tentativo di istanziare gli oggetti di quella classe, è un errore di compilazione.

Vengono chiamate le classi che possono essere utilizzate per creare un'istanza di oggetti concrete classes.

Esempio di classe astratta

Considera il seguente esempio in cui la classe genitore fornisce un'interfaccia alla classe base per implementare una funzione chiamata getArea() -

#include <iostream>
 
using namespace std;
 
// Base class
class Shape {
   public:
      // pure virtual function providing interface framework.
      virtual int getArea() = 0;
      void setWidth(int w) {
         width = w;
      }
   
      void setHeight(int h) {
         height = h;
      }
   
   protected:
      int width;
      int height;
};
 
// Derived classes
class Rectangle: public Shape {
   public:
      int getArea() { 
         return (width * height); 
      }
};

class Triangle: public Shape {
   public:
      int getArea() { 
         return (width * height)/2; 
      }
};
 
int main(void) {
   Rectangle Rect;
   Triangle  Tri;
 
   Rect.setWidth(5);
   Rect.setHeight(7);
   
   // Print the area of the object.
   cout << "Total Rectangle area: " << Rect.getArea() << endl;

   Tri.setWidth(5);
   Tri.setHeight(7);
   
   // Print the area of the object.
   cout << "Total Triangle area: " << Tri.getArea() << endl; 

   return 0;
}

Quando il codice precedente viene compilato ed eseguito, produce il seguente risultato:

Total Rectangle area: 35
Total Triangle area: 17

Puoi vedere come una classe astratta ha definito un'interfaccia in termini di getArea () e altre due classi hanno implementato la stessa funzione ma con algoritmi diversi per calcolare l'area specifica della forma.

Strategia di progettazione

Un sistema orientato agli oggetti potrebbe utilizzare una classe base astratta per fornire un'interfaccia comune e standardizzata appropriata per tutte le applicazioni esterne. Quindi, attraverso l'ereditarietà da quella classe base astratta, si formano classi derivate che operano in modo simile.

Le capacità (cioè le funzioni pubbliche) offerte dalle applicazioni esterne sono fornite come funzioni virtuali pure nella classe base astratta. Le implementazioni di queste funzioni virtuali pure sono fornite nelle classi derivate che corrispondono ai tipi specifici dell'applicazione.

Questa architettura consente inoltre di aggiungere facilmente nuove applicazioni a un sistema, anche dopo che il sistema è stato definito.