Primero: enfatizar un concepto

Definir una función como virtual no significa que la función no vaya a ser implementada.

Definirla como función virtual es para permitir usar un puntero de la clase base para llamar a esta función de la subclase.

Definir una función como función virtual pura es lo que representa que la función no ha sido implementada.

Definir una función virtual pura es para implementar una interfaz, actuando como una especificación: los programadores que hereden esta clase deben implementar esta función.

1. Introducción

Supongamos que tenemos la siguiente jerarquía de clases:

Ejemplo

class A { public:     virtual void foo()     {         cout<<"A::foo() is called"<<endl;     } }; class B:public A { public:     void foo()     {         cout<<"B::foo() is called"<<endl;     } }; int main(void) {     A *a = new B();     a->foo();   // Aquí, aunque a es un puntero que apunta a A, ¡la función llamada (foo) es la de B!     return 0; }

Este ejemplo es una aplicación típica de las funciones virtuales. A través de este ejemplo, quizás ya tengas algún concepto sobre las funciones virtuales. Su naturaleza "virtual" radica en el llamado "enlace diferido" o "enlace dinámico": la llamada a una función de clase no se determina en el momento de la compilación, sino en el momento de la ejecución. Dado que al escribir el código no se puede determinar si se llama a la función de la clase base o a la de alguna clase derivada, se denomina función "virtual".

Las funciones virtuales solo pueden lograr el efecto del polimorfismo mediante punteros o referencias.


Funciones virtuales puras en C++

I. Definición

 

Una función virtual pura es una función virtual declarada en la clase base; no tiene definición en la clase base, pero se requiere que cualquier clase derivada defina su propio método de implementación. El método para implementar una función virtual pura en la clase base es agregar después del prototipo de la función:=0:

 
virtual void funtion1()=0

II. Razones de su introducción

  

1. Para facilitar el uso de las características del polimorfismo, a menudo necesitamos definir funciones virtuales en la clase base.

  

2. En muchos casos, no es razonable que la clase base genere objetos por sí misma. Por ejemplo, "Animal" como clase base puede derivar subclases como "Tigre" y "Pavo real", pero que "Animal" genere un objeto por sí mismo es claramente irrazonable.

  

Para resolver los problemas anteriores, se introduce el concepto de función virtual pura, definiendo la función como función virtual pura (método:virtual ReturnType Function()= 0;), entonces el compilador exige que en la clase derivada se reescriba obligatoriamente para lograr el polimorfismo. Al mismo tiempo, una clase que contiene funciones virtuales puras se denomina clase abstracta, y no puede generar objetos. De esta manera, se resuelven bien los dos problemas anteriores.

Una clase que declara funciones virtuales puras es una clase abstracta. Por lo tanto, el usuario no puede crear instancias de la clase, solo puede crear instancias de sus clases derivadas.

La característica más destacada de las funciones virtuales puras es: deben volver a declarar la función en la clase derivada (sin el "= 0" al final; de lo contrario, la clase derivada tampoco puede ser instanciada), y a menudo no tienen definición en la clase abstracta.

El propósito de definir funciones virtuales puras es que las clases derivadas solo hereden la interfaz de la función.

El significado de las funciones virtuales puras es permitir que todos los objetos de clase (principalmente objetos de clases derivadas) puedan ejecutar la acción de la función virtual pura, pero la clase no puede proporcionar una implementación predeterminada razonable para la función virtual pura. Por lo tanto, la declaración de una función virtual pura en la clase está diciendo al diseñador de la subclase: "Debes proporcionar una implementación de la función virtual pura, pero no sé cómo la implementarás".


Introducción a las clases abstractas

Una clase abstracta es un tipo especial de clase creada con fines de abstracción y diseño; se encuentra en los niveles superiores de la jerarquía de herencia.

(1) Definición de clase abstracta:Se denomina clase abstracta a una clase que contiene funciones virtuales puras.

(2) Función de la clase abstracta:El papel principal de la clase abstracta es organizar las operaciones relacionadas como interfaces dentro de una jerarquía de herencia, proporcionando a las clases derivadas una raíz común. Las clases derivadas implementarán concretamente las operaciones que actúan como interfaces en su clase base. Por lo tanto, la clase derivada describe en realidad la semántica común de un conjunto de interfaces de operación de las subclases; esta semántica también se transmite a las subclases, que pueden implementarla concretamente o transmitirla a sus propias subclases.

(3) Precauciones al usar clases abstractas:

  • Una clase abstracta solo puede usarse como clase base, y la implementación de sus funciones virtuales puras la proporcionan las clases derivadas. Si en la clase derivada no se redefinen las funciones virtuales puras, sino que solo se heredan las de la clase base, entonces la clase derivada sigue siendo una clase abstracta. Si la clase derivada proporciona la implementación de las funciones virtuales puras de la clase base, entonces ya no es una clase abstracta, sino una clase concreta que puede crear objetos.
  • Una clase abstracta no puede definir objetos.

Resumen:

  • 1. Una función virtual pura se declara de la siguiente manera:virtual void funtion1()=0;Una función virtual pura no tiene definición en absoluto; se utiliza para regular el comportamiento de las clases derivadas, es decir, como interfaz. Una clase que contiene funciones virtuales puras es una clase abstracta; una clase abstracta no puede definir instancias, pero puede declarar punteros o referencias a clases concretas que implementen dicha clase abstracta.

  • 2. Una función virtual se declara de la siguiente manera:virtual ReturnType FunctionName(Parameter)Una función virtual debe implementarse; si no se implementa, el compilador mostrará un error, con un mensaje como:

    error LNK****: unresolved external symbol "public: virtual void __thiscall ClassName::virtualFunctionName(void)"
  • 3. En cuanto a las funciones virtuales, la clase padre y la subclase tienen sus propias versiones. Cuando se invocan de forma polimórfica, se realiza un enlace dinámico.

  • 4. En una subclase que implementa una función virtual pura, dicha función se convierte en una función virtual en la subclase; la subclase de la subclase (es decir, la clase nieta) puede sobrescribir esa función virtual, y cuando se invoca de forma polimórfica, se realiza un enlace dinámico.

  • 5. Las funciones virtuales son el mecanismo en C++ para implementar el polimorfismo. La idea central es acceder a las funciones definidas en las clases derivadas a través de la clase base.

  • 6. Cuando se asigna memoria dinámicamente en el montón, el destructor debe ser una función virtual, pero no es necesario que sea virtual pura.

  • 7. Las funciones amigas no son funciones miembro; solo las funciones miembro pueden ser virtuales, por lo que las funciones amigas no pueden ser funciones virtuales. Sin embargo, el problema de la virtualidad de las funciones amigas se puede resolver haciendo que la función amiga llame a una función miembro virtual.

  • 8. El destructor debe ser una función virtual; se invocará el destructor del tipo de objeto correspondiente. Por lo tanto, si el puntero apunta a un objeto de la subclase, se llamará al destructor de la subclase y luego automáticamente al destructor de la clase base.

Una clase con funciones virtuales puras es una clase abstracta; no puede generar objetos, solo puede derivar. Si las funciones virtuales puras de sus clases derivadas no han sido sobrescritas, entonces sus clases derivadas también son clases abstractas.

Definir funciones virtuales puras es precisamente para que la clase base no pueda ser instanciada, porque instanciar una estructura de datos tan abstracta no tiene sentido en sí mismo, ni tampoco tiene sentido proporcionar una implementación.

En realidad, personalmente creo que la introducción de las funciones virtuales puras tiene dos propósitos:

  • 1. Por seguridad: para evitar cualquier resultado desconocido que requiera ser definido explícitamente pero que, por descuido, no lo sea, recordando a las subclases que hagan la implementación correspondiente.
  • 2. Por eficiencia, no la eficiencia de ejecución del programa, sino la eficiencia de codificación.

Dirección del artículo original: https://blog.csdn.net/hackbuteer1/article/details/7558868