c++ - sirve - ¿Por qué tiene sentido dar definición para una función virtual pura?
polimorfismo puro c++ (5)
Scott dijo en Effective C ++, 3rd Edition, pág. 43 que para hacer una clase abstracta, solo necesitamos darle un destructor virtual puro:
class AWOV { // AWOV = "Abstract w/o Virtuals"
public:
virtual ~AWOV() = 0; // declare pure virtual destructor
};
Luego, continuó diciendo que hay un giro: debemos proporcionar una definición para el destructor virtual puro:
AWOV::~AWOW() {} // definition of pure virtual dtor
Mi pregunta es, especificando = 0
, para funciones virtuales puras, estamos diciendo que la función no puede tener ninguna definición para la clase donde se declara esta función virtual pura.
¿Por qué está bien proporcionar una definición (incluso si está vacía) para el destructor virtual puro aquí?
"estamos diciendo que la función no puede tener ninguna definición para la clase donde se declara esta función virtual pura".
Eso no es lo que significa puro virtual. Puro virtual solo significa que la clase contenedora no se puede crear una instancia (es abstracta), por lo que tiene que ser subclasificada, y las subclases deben reemplazar el método. P.ej,
struct A {
virtual ~A() = 0;
};
A::~A() {}
struct B : A {};
int main()
{
A a; // error
B b; // ok
}
Aquí, el destructor B
se define implícitamente. Si se tratara de otro método que sea puramente virtual, tendría que anularlo explícitamente:
struct A {
virtual void foo() = 0;
};
void A::foo() {}
struct B : A {};
int main()
{
B b; // error
}
Proporcionar una definición para un método virtual puro es deseable cuando la clase base debe ser abstracta pero aún así proporcionar algún comportamiento predeterminado.
En el caso específico de un destructor, debe proporcionarse porque se llamará automáticamente cuando se destruyan las instancias de las subclases. Un programa que intente crear una instancia de una subclase de una clase con un destructor virtual puro sin una definición no pasará el enlazador.
Al hacer que una función sea puramente virtual obligamos al usuario de la clase a reemplazar la función con otra en la clase derivada.
La función de clase base todavía se puede llamar con BaseClass::myfunction(...)
Ahora la clase base puede querer proporcionar alguna funcionalidad central que la clase derivada puede usar si así lo desea.
Esto no es necesario para todas las funciones virtuales puras . De ningún modo.
De esta forma, las clases derivadas seguirán siendo obligadas a anular la implementación , pero habrá una implementación predeterminada en la clase base, en caso de que necesite llamarla . Y ese es el caso aquí, porque se trata de un destructor: cuando se destruye un objeto derivado, se llama a su destructor y también se llama a sus destructores de clases base . Es por eso que necesita una implementación para A::~A
Haciéndolo puras fuerzas derivadas (no abstractas) de las clases para implementar las propias.
Proporcionar una implementación permite a las clases derivadas invocar el comportamiento de la clase base (lo que hacen los destructores por defecto).
Hay 2 casos.
Puro destructor virtual
Este caso es tratado específicamente por la norma.
12.4 Destructores [class.dtor]
9) Un destructor puede ser declarado
virtual
(10.3) o purovirtual
(10.4); Si se crea algún objeto de esa clase o cualquier clase derivada en el programa, se definirá el destructor. Si una clase tiene una clase base con un destructor virtual, su destructor (ya sea declarado por el usuario o implícitamente) es virtual.
El caso del destructor es diferente porque se llama a todos los destructores en una búsqueda jerárquica de herencia (suponiendo una eliminación correcta) en orden inverso de construcción, aunque no explícitamente. Por lo tanto, se llama al destructor de la clase base cuando el objeto se elimina, por eso necesita una implementación.
Puro método virtual
Estos difieren de los destructores en que no se requiere que sean implementados, ni tampoco necesitan una implementación. La diferencia para el requisito faltante es que cuando se llama a Derived::foo()
, no llama automáticamente a Base::foo()
(no es que pueda, ya que puede o no puede implementarse).
Por qué querría implementar un método virtual
puro depende del caso. Considero que el especificador puro es una sugerencia para el programador, a diferencia de lo relacionado con la lógica. Le dice a usted, el programador, que debe implementar ese método . Realmente no importa si la clase base tiene una implementación o no.
Especificando = 0, para funciones virtuales puras, estamos diciendo que la función no puede tener ninguna definición para la clase donde se declara esta función virtual pura.
Realmente no. Usted está diciendo que las clases derivadas no abstractas tienen que anular esa función. Esto no te impide implementarlo tú mismo.