Abstract class
Define un tipo abstracto que no puede ser instanciado, pero puede ser utilizado como clase base.
Contenidos |
Sintaxis
Una función pure virtual es una función virtual cuyo declarador tiene la siguiente sintaxis:
declarador
especificador-virtual
(opcional)
=
0
|
|||||||||
Aquí la secuencia
= 0
se conoce como
pure-specifier
, y aparece inmediatamente después del
declarator
o después del
virt-specifier
opcional (
override
o
final
).
pure-specifier no puede aparecer en una definición de función miembro o friend declaración.
struct Base { virtual int g(); virtual ~Base() {} }; struct A : Base { // CORRECTO: declara tres funciones miembro virtuales, dos de ellas puras virtual int f() = 0, g() override = 0, h(); // CORRECTO: el destructor también puede ser puro ~A() = 0; // ERROR: especificador puro en una definición de función virtual int b() = 0 {} };
Una clase abstracta es una clase que define o hereda al menos una función para la cual el final overrider es pure virtual .
Explicación
Las clases abstractas se utilizan para representar conceptos generales (por ejemplo, Shape, Animal), que pueden utilizarse como clases base para clases concretas (por ejemplo, Circle, Dog).
No se pueden crear objetos de una clase abstracta (excepto para subobjetos base de una clase derivada de ella) y no se pueden declarar miembros de datos no estáticos cuyo tipo sea una clase abstracta.
Los tipos abstractos no pueden utilizarse como tipos de parámetros, como tipos de retorno de funciones, o como el tipo de una conversión explícita (nótese que esto se verifica en el punto de definición y llamada de función, ya que en el punto de declaración de función los tipos de parámetros y retorno pueden estar incompletos).
Se pueden declarar punteros y referencias a una clase abstracta.
struct Abstract { virtual void f() = 0; // virtual puro }; // "Abstract" es abstracta struct Concrete : Abstract { void f() override {} // virtual no puro virtual void g(); // virtual no puro }; // "Concrete" no es abstracta struct Abstract2 : Concrete { void g() override = 0; // redefinidor virtual puro }; // "Abstract2" es abstracta int main() { // Abstract a; // Error: clase abstracta Concrete b; // OK Abstract& a = b; // OK para referenciar base abstracta a.f(); // despacho virtual a Concrete::f() // Abstract2 a2; // Error: clase abstracta (el redefinidor final de g() es puro) }
La definición de una función virtual pura puede ser proporcionada (y debe ser proporcionada si la virtual pura es el
destructor
): las funciones miembro de la clase derivada pueden llamar a la función virtual pura de la base abstracta usando el id de función calificado. Esta definición debe ser proporcionada fuera del cuerpo de la clase (la sintaxis de una declaración de función no permite tanto el especificador puro
= 0
como un cuerpo de función).
Realizar una llamada virtual a una función virtual pura desde un constructor o el destructor de la clase abstracta es comportamiento indefinido (independientemente de si tiene una definición o no).
struct Abstract { virtual void f() = 0; // virtual pura virtual void g() {} // virtual no pura ~Abstract() { g(); // OK: llama a Abstract::g() // f(); // comportamiento indefinido Abstract::f(); // OK: llamada no virtual } }; // definición de la función virtual pura void Abstract::f() { std::cout << "A::f()\n"; } struct Concrete : Abstract { void f() override { Abstract::f(); // OK: llama a la función virtual pura } void g() override {} ~Concrete() { g(); // OK: llama a Concrete::g() f(); // OK: llama a Concrete::f() } };
Informes de defectos
Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares publicados anteriormente de C++.
| DR | Aplicado a | Comportamiento publicado | Comportamiento correcto |
|---|---|---|---|
| CWG 390 | C++98 | podría llamarse a un destructor virtual puro no definido | se requiere una definición en este caso |
| CWG 2153 | C++98 | pure-specifier podría aparecer en declaraciones friend | prohibido |