Disponible la nueva versión "donationware" 7.3 de OrganiZATOR
Descubre un nuevo concepto en el manejo de la información.
La mejor ayuda para sobrevivir en la moderna jungla de datos la tienes aquí.

Curso C++

[Home]  [Inicio]  [Índice]


4.11.8c   Clases abstractas

§1  Sinopsis

La abstracción es un recurso de la mente (quizás el más característico de nuestra pretendida superioridad respecto del mundo animal). Por su parte, los lenguajes de programación permiten expresar la solución de un problema de forma comprensible simultáneamente por la máquina y el humano. Constituyen un puente entre la abstracción de la mente y una serie de instrucciones ejecutables por un dispositivo electrónico. En consecuencia, la capacidad de abstracción es una característica deseable de los lenguajes artificiales, pues cuanto mayor sea, mayor será su aproximación al lado humano. Es decir, con la imagen existente en la mente del programador. En este sentido, la introducción de las clases en los lenguajes orientados a objetos ha representado un importante avance respecto de la programación tradicional y dentro de ellas, las denominadas clases abstractas son las que representan el mayor grado de abstracción.

De hecho, las clases abstractas presentan un nivel de "abstracción" tan elevado que no sirven para instanciar objetos de ellas. Representan los escalones más elevados de algunas jerarquías de clases y solo sirven para derivar otras clases, en las que se van implementando detalles y concreciones, hasta que finalmente presentan un nivel de definición suficiente que permita instanciar objetos concretos. Se suelen utilizar en aquellos casos en que se quiere que una serie de clases mantengan una cierta característica o interfaz común. Por esta razón a veces se dice de ellas que son pura interfaz.

Resulta evidente en el ejemplo de la figura que los diversos tipos de motores tienen características diferentes. Realmente tienen poco en común un motor eléctrico de corriente alterna y una turbina de vapor. Sin embargo, la construcción de una jerarquía en la que todos motores desciendan de un ancestro común, la clase abstracta "Motores", presenta la ventaja de unificar la interfaz. Aunque evidentemente su definición será tan "abstracta", que no pueda ser utilizada para instanciar directamente ningún tipo de motor. El creador del lenguaje dice de ellas que soportan la noción de un concepto general del que solo pueden utilizarse variantes más concretas [2].

§2  Clases abstractas

Una clase abstracta es la que tiene al menos una función virtual pura (como hemos visto, una función virtual es especificada como "pura" haciéndola igual a cero 4.11.8a).

Nota: recordemos que las clases que tienen al menos una función virtual (o virtual pura) se denominan clases polimórficas ( 4.11.8). Resulta por tanto, que todas las clases abstractas son también polimórficas, pero no necesariamente a la inversa.

§3  Reglas de uso:
  • Una clase abstracta solo puede ser usada como clase base para otras clases, pero no puede ser instanciada para crear un objeto 1.
  • Una clase abstracta no puede ser utilizada como argumento o como retorno de una función 2.
  • Si puede declararse punteros-a-clase abstracta 3 [1].
  • Se permiten referencias-a-clase abstracta, suponiendo que el objeto temporal no es necesario en la inicialización 4.
§4  Ejemplo


class Figura {       // clase abstracta (CA)
  point centro;
    ...
  public:
  getcentro() { return center; }
  mover(point p) { centro = p; dibujar(); }
  virtual void rotar(int) = 0;   // función (método) virtual pura
  virtual void dibujar() = 0;    // función (método) virtual pura
  void brillo(int);              // método normal -definición off-line-
   ...
};
...
Figura x;            // ERROR: intento de instanciar una CA.1
Figura* sptr;        // Ok: puntero a CA. 3
Figura f();          // ERROR: función NO puede devolver tipo CA. 2
int g(Figura s);     // ERROR: CA NO puede ser argumento de función 2
Figura& h(Figura&);  // Ok: devuelve tipo "referencia-a-CA" 4
int h(Figura&);      // Ok: "referencia-a-CA" si puede ser argumento 4


§5  Suponiendo que A sea una clase abstracta y que D sea una clase derivada inmediata de ella, cada función virtual pura fvp de A, para la que D no aporte una definición, se convierte en función virtual pura para D. En cuyo caso, D resulta ser también una clase abstracta.

Por ejemplo, suponiendo la clase Figura definida previamente:

class Circulo : public Figura { // Circulo deriva de una C.A.
   int radio;         // privado por defecto
   public:
   void rotar(int);   // convierte rotar en función no virtual
};

En esta clase, el método heredado Circulo::dibujar() es una función virtual pura.  Sin embargo, Circulo::rotar() no lo es (suponemos que definición se efectúa off-line). En consecuencia, Circulo es también una clase abstracta. En cambio, si hacemos:

class Circulo : public Figura { // Circulo deriva de una C.A.
   int radio;
   public:
   void rotar(int);   // convierte rotar en función no virtual pura
   void dibujar();    // convierte dibujar en función no virtual pura
};

la clase Circulo deja de ser abstracta.


§6  Las funciones-miembro pueden ser llamadas desde el constructor de una clase abstracta, pero la llamada directa o indirecta de una función virtual pura desde tal constructor puede provocar un error en tiempo de ejecución. Sin embargo, son permitidas disposiciones como la siguiente:

class CA {        // clase abstracta
   public:
   virtual void foo() = 0;  // foo virtual pura
   CA() {         // constructor
      CA::foo();  // Ok.
};
...
void CA::foo() {  // definición en algún sitio
   ...

La razón es la ya señalada ( 4.11.8a), de que la utilización del operador :: de acceso a ámbito anula el mecanismo de funciones virtuales.

  Inicio.


[1]  Precisamente, la invocación de métodos de clases derivadas mediante punteros a la superclase, es una de las características esenciales de la tecnología COM de Microsoft.

[2]  Stroustrup & Ellis: ACRM  §10.3.