Clase abstracta
Define un tipo abstracto del cual no pueden crearse objetos, pero puede usarse como clase base.
Contenido |
[editar] Sintaxis
Una función virtual pura es una función virtual cuyo declarador tiene la siguiente sintaxis:
declarador especificador-virtual(opcional) = 0
|
|||||||||
Aquí la secuencia = 0
se conoce como el especificador-puro, y aparece ya sea inmediatamente después del declarador o después del especificador-virtual opcional (override o final).
El especificador-puro no puede aparecer en una definición de una función miembro.
struct Base { virtual int g(); virtual ~Base() {} }; struct A : Base { // de acuerdo: declara tres funciones miembro virtuales, dos de ellas puras virtual int f() = 0, g() override = 0, h(); // de acuerdo: el destructor también puede ser puro ~A() = 0; // ERROR: el especificador-puro en la definición de una función. virtual int b() = 0 {} };
Una clase abstracta es una clase que bien define o hereda al menos una función para la que el reemplazo final es virtual puro.
[editar] Explicación
Las clases abstractas se usan para representar conceptos generales (p. ej., Figura, Animal), que pueden ser usados como clases base para clases concretas (p. ej., Cuadrado, Perro).
No pueden crearse objetos de una clase abstracta (excepto los subobjetos base de una clase derivada de ella), y no pueden declararse miembros de datos no estáticos de una clase abstracta.
Los tipos abstractos no se pueden usar como tipos de parámetro, como tipos de retorno de una función, o como el tipo de una conversión explícita. Observa que esto se revisa en el punto de definición y llamada de función, ya que en el punto de la declaración de función, el tipo de retorno puede estar incompleto.
Pueden declararse punteros y referencias a una clase abstracta.
struct Abstracta { virtual void f() = 0; // virtual pura }; // "Abstracta" es abstracta struct Concreta : Abstracta { void f() override {} // no virtual pura virtual void g(); // no virtual pura }; // "Concreta" no es abstracta struct Abstracta2 : Concreta { void g() override = 0; // reemplazo puro virtual }; // "Abstracta2" es abstracta int main() { // Abstracta a; // ERROR: clase abstracta Concreta b; // de acuerdo Abstract& a = b; // de acuerdo para referencias la base abstracta a.f(); // despacho virtual a Concreta::f() // Abstracta2 a2; // ERROR: clase abstracta (reemplazo final de g() es puro) }
La definición de una función virtual pura puede suministrarse (y tiene que ser suministrada si la virtual pura es el destructor): las funciones miembro de la clase derivadas son libres de llamar a la función pura virtual de la clase base utilizando la función calificada con el nombre de la clase base. Esta definición tiene que suministrarse fuera del cuerpo de la clase (la sintaxis de una declaración de función no permite a la vez el especificador puro = 0
y el cuerpo de una función).
Realizar una llamada virtual a una función pura virtual desde un constructor o el destructor de la clase abstracta es comportamiento indefinido (independientemente de si tiene una definición o no).
struct Abstracta { virtual void f() = 0; // virtual pura virtual void g() {} // no virtual pura ~Abstracta() { g(); // de acuerdo: llama a Abstracta::g() // f(); // comportamiento indefinido Abstracta::f(); // de acuerdo: llamada no virtual } }; // definición de la función virtual pura void Abstracta::f() { std::cout << "A::f()\n"; } struct Concreta : Abstracta { void f() override { Abstracta::f(); // de acuerdo: llama a la función virtual pura } void g() override {} ~Concreta() { g(); // de acuerdo: llama a Concreta::g() f(); // de acuerdo: llama a Concreta::f() } };
[editar] Informes de defectos
Los siguientes informes de defectos de cambio de comportamiento se aplicaron de manera retroactiva a los estándares de C++ publicados anteriormente.
ID | Aplicado a | Comportamiento según lo publicado | Comportamiento correcto |
---|---|---|---|
CWG 390 | C++98 | podría llamarse a un destructor puro indefinido | se requiere una definición en este caso |