2009-04-12 6 views

Respuesta

43

La referencia a la respuesta de Jim, que era excelente por cierto, solo describía cuándo y dónde usar las directivas. Otra parte de la respuesta es por qué son necesarios de todos modos? Muchos idiomas se llevan bien sin ellos, ¿verdad? Al diseñar aspectos del lenguaje pascal de objetos Delphi, la programación orientada a objetos (OOP) ha estado en la corriente principal durante varios años. Durante este tiempo, se observó que el uso de muchos de los lenguajes que habían adoptado esos conceptos (Turbo Pascal, C++, etc.) para desarrollar marcos de aplicación sufría de lo que llamé el problema de la "versión 2".

Supongamos que desarrolla un marco impresionante utilizando el lenguaje X y lo lanzó como la versión 1. Sus usuarios comentaron todo lo que podía hacer y se volvió muy utilizado. Enjuague con éxito, decide lanzar la versión 2 con aún más genialidad. Usted específicamente se aseguró de que fuera totalmente compatible con versiones anteriores. De repente, los usuarios comenzaron a informar comportamientos extraños. Sus propios métodos virtuales fueron llamados en tiempos extraños. Muchos informaron que su código anterior no se compilaría con la nueva versión. Extraño. Todos los mismos objetos, métodos y funcionalidad aún permanecen. Todo lo que hizo fue agregar algunos métodos virtuales a algunas clases base, algunos tipos de objetos nuevos y algunas nuevas funcionalidades opcionales. ¿Que pasó?

Las directivas de anulación y reintroducción sirven para eliminar este problema al requerir que, para realmente anular un método virtual, debe utilizar la directiva de anulación en lugar de la directiva virtual. Si introduce su propio método virtual que tiene el mismo nombre que uno de los métodos virtuales de sus antepasados, el compilador ahora lo advierte, pero seguirá haciendo lo correcto. En este caso, el uso de la reintroducción no solo suprime esa advertencia, sino que también sirve para documentar en la fuente en la que se pretendía hacerlo.

Sin las directivas de anulación y reintroducción, no sería capaz de evolucionar continuamente su estructura sin temor a romper todos sus usuarios. Y si tus usuarios tuvieran que hacer modificaciones masivas cada vez que se lanzara una nueva versión, entonces detestarían adoptar la nueva versión. Finalmente, usar "anular" también permite al diseñador del marco cambiar el tipo de virtual en los antepasados ​​sin romper el código de usuario. Por ejemplo, en Delphi, muchos métodos están marcados como "dinámico", que es una forma de análisis de polimorfismo del método de tiempo de ejecución basado en tabla. No funciona tan rápido como un servidor virtual común, por lo que generalmente se usa para métodos que rara vez se anulan y/o son respuestas a acciones del usuario donde nunca se nota la sobrecarga adicional. Supongamos que en V1 del marco un método se marcó como "dinámico" pero en la práctica terminó anulándose y se llamó más de lo que se pretendía. En V2, puede cambiarlo a "virtual" sin temor a que se rompa el código del usuario.

Objeto de Delphi El lenguaje Pascal no es el único idioma que reconoce este problema. C# requiere el uso de una directiva "anular" por el mismo motivo. El comité de estándares de C++ finalmente está reconociendo el problema y está modificando el lenguaje para apoyarlo ... más o menos. En C++, si el nombre de un método y la lista de parámetros coinciden con los de un ancestro, entonces se trata de una anulación (¡incluso si no dice "virtual" en el descendiente!).Para el próximo nuevo estándar de C++, si especifica "virtual" y las firmas no coinciden, entonces es un nuevo método virtual introducido en la clase actual. Si hay una coincidencia de firma con el ancestro y el escritor no se predijo omitir, la palabra clave "nueva" se usa para indicar al compilador que se trata de un nuevo virtual para esta clase.

+0

FWIW, Wirth también tenía una palabra clave explícita 'override' en su/Object Pascal de Apple (para Mac), muy probablemente por la misma razón. Y MS QuickPascal también lo tenía. Pero ninguno tenía un 'reintroducir'. –

+0

Explicación clara y concisa: 10/10 –

8

La directiva de anulación se utiliza para anular los métodos virtuales en las clases heredadas.

La directiva reintroduce se utiliza para declarar un método con el mismo nombre que en la superclase, pero con diferentes parámetros.

+4

reintroduce solo es necesario si el método (con los mismos parámetros) en la superclase es virtual. Si no es virtual, no hay necesidad de "reintroducir" porque el método de la superclase se ocultará de todos modos. –

6

¿Y cuándo no debería utilizar la palabra clave heredada en los métodos reemplazados?

Básicamente, la respuesta es cuando no desea que se ejecute el método heredado. Tenga cuidado, ya que no permitir que se ejecute un método heredado puede romper la funcionalidad de un objeto heredado de una manera no deseada, así que asegúrese de no introducir ningún efecto secundario no deseado.

Como ejemplo, imagine que desea anular por completo una función heredada llamada ApplyDiscount, pero alguien ha codificado el porcentaje de descuento en la clase ancestro. Si llama a ApplyDiscount heredado, anulará su código o calculará un valor que luego anulará; en este caso, no podría llamar heredado y aplicar el descuento usted mismo.

(Este es un ejemplo contribuido de modo que si alguien puede pensar en una mejor favor agregarlo.)

1

Hay muchas circunstancias en las que no desea llamar heredada en un método reemplazado.

En algunas bibliotecas que uso use, el método base arroja un error (ENotImplified o similar). Obviamente, en ese caso, no desea llamar a heredado o su código también arrojaría el error.

Algunas de mis clases tienen una implementación predeterminada que funciona en la mayoría de los casos. El método solo se reemplaza para reemplazar el predeterminado, y no es necesario llamar al predeterminado.

Por ejemplo, la función GST (= impuesto sobre las ventas) en mi objeto financiero base devuelve 12.5% ​​del monto ExGst e IncGst devuelve ExGst + GST.

En mis objetos de Compensación de ingresos, GST siempre devuelve 0, por lo que no es necesario llamar a la función heredada.

Cuestiones relacionadas