Interfaces en C ++ (clases abstractas)

Una interfaz describe el comportamiento o las capacidades de una clase C ++ sin comprometerse con una implementación particular de esa clase.

Las interfaces C ++ se implementan usando abstract classes y estas clases abstractas no deben confundirse con la abstracción de datos, que es un concepto de mantener los detalles de implementación separados de los datos asociados.

Una clase se hace abstracta declarando al menos una de sus funciones como pure virtualfunción. Una función virtual pura se especifica colocando "= 0" en su declaración de la siguiente manera:

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

El propósito de un abstract class(a menudo denominado ABC) es proporcionar una clase base apropiada de la que otras clases pueden heredar. Las clases abstractas no se pueden utilizar para crear instancias de objetos y solo sirven comointerface. Intentar crear una instancia de un objeto de una clase abstracta provoca un error de compilación.

Por lo tanto, si se necesita instanciar una subclase de un ABC, debe implementar cada una de las funciones virtuales, lo que significa que admite la interfaz declarada por el ABC. No anular una función virtual pura en una clase derivada y luego intentar crear una instancia de los objetos de esa clase es un error de compilación.

Las clases que se pueden utilizar para crear instancias de objetos se denominan concrete classes.

Ejemplo de clase abstracta

Considere el siguiente ejemplo donde la clase padre proporciona una interfaz a la clase base para implementar una función llamada 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;
}

Cuando se compila y ejecuta el código anterior, produce el siguiente resultado:

Total Rectangle area: 35
Total Triangle area: 17

Puede ver cómo una clase abstracta definió una interfaz en términos de getArea () y otras dos clases implementaron la misma función pero con un algoritmo diferente para calcular el área específica de la forma.

Estrategia de diseño

Un sistema orientado a objetos puede utilizar una clase base abstracta para proporcionar una interfaz común y estandarizada apropiada para todas las aplicaciones externas. Luego, a través de la herencia de esa clase base abstracta, se forman clases derivadas que operan de manera similar.

Las capacidades (es decir, las funciones públicas) que ofrecen las aplicaciones externas se proporcionan como funciones virtuales puras en la clase básica abstracta. Las implementaciones de estas funciones virtuales puras se proporcionan en las clases derivadas que corresponden a los tipos específicos de la aplicación.

Esta arquitectura también permite agregar fácilmente nuevas aplicaciones a un sistema, incluso después de que se haya definido el sistema.