virtuales que puro polimorfismo objeto modificador herencia funciones clase abstracta c++ oop methods virtual

que - polimorfismo puro c++



¿Cuándo es apropiado usar métodos virtuales? (10)

Entiendo que los métodos virtuales permiten que una clase derivada anule los métodos heredados de una clase base. ¿Cuándo es apropiado / inapropiado utilizar métodos virtuales? No siempre se sabe si una clase será subclasificada. ¿Debería hacerse todo virtual, solo "en caso?" ¿O eso causará una sobrecarga significativa?


Cuando diseñe una clase, debe tener una idea bastante buena de si representa una interfaz (en cuyo caso usted marca los métodos reemplazables apropiados y el destructor virtual) O si está diseñado para ser tal como está, posiblemente componiendo o componiendo con otros objetos. .

En otras palabras, su intención para la clase debe ser su guía. Hacer que todo sea virtual es a menudo excesivo y, a veces, confuso con respecto a qué métodos están destinados a soportar el polimorfismo en tiempo de ejecución.


Echa un vistazo a los patrones de diseño . Si su código / diseño es uno de estos o similar, use la función virtual. De lo contrario, intente this


Es una pregunta difícil. Pero hay algunas pautas / regla de los pulgares a seguir.

  1. Siempre que no necesite derivar de una clase, entonces no escriba ningún método virtual , una vez que necesite derivar, solo haga virtual aquellos métodos que necesite personalizar en la clase secundaria.
  2. Si una clase tiene un método virtual , el destructor será virtual (fin de la discusión).
  3. Intente seguir el lenguaje NVI (Interfaz no virtual), haga que virtual método virtual no sea público y proporcione envoltorios públicos a cargo de evaluar las condiciones previas y posteriores, para que las clases derivadas no puedan romperlas accidentalmente.

Creo que son lo suficientemente simples. Definitivamente, dejo de lado la parte ABI de la reflexión, solo es útil cuando se entregan DLL.


Lo que quiero decir es que si desea usar el puntero de la clase principal para apuntar a la instancia de la clase secundaria y usar sus métodos, entonces debería usar métodos virtuales.


Los métodos virtuales son una forma de lograr el polimorfismo. Se utilizan cuando se desea definir una acción en un nivel más abstracto, de modo que es realmente imposible implementarla porque es demasiado general. Solo en las clases derivadas puedes decir cómo realizar esa acción. Pero con la definición de un método virtual se crea un requisito, que agrega rigidez a la jerarquía de clases. Esto puede ser recomendable o no, depende de lo que esté tratando de obtener y de su propio gusto.


Por ejemplo, las funciones de los miembros en Java son 100% virtuales. En C ++ se considera como una penalización de tiempo de llamada de función / tamaño de código. Además, una función no virtual garantiza que la implementación de la función siempre será la misma (utilizando el objeto / referencia de la clase base). Scott Meyers en "Effective C ++" lo discute en más detalles.


Primero, un comentario ligeramente pedante: en C ++ standard, las llamamos funciones miembro, no métodos, aunque los dos términos son equivalentes.

Veo dos razones para NO hacer que una función de miembro sea virtual.

  • "YAGNI" - "No lo vas a necesitar". Si no está seguro de que se derivará una clase, suponga que no lo será y no haga que las funciones de miembro sean virtuales. Nada dice "no derive de mí" como un destructor no virtual, por cierto. También se trata de la intención. Si no es su intención utilizar la clase de forma polimórfica, no haga nada virtual. Si arbitrariamente haces miembros virtuales, estás invitando a abusar del Principio de Sustitución de Liskov y esas clases de errores son difíciles de localizar y resolver.
  • Rendimiento / huella de memoria. Una clase que no tiene funciones miembro virtuales no requiere una tabla virtual (tabla virtual, utilizada para redirigir las llamadas polimórficas a través de un puntero de clase base) y, por lo tanto, ocupa menos espacio en la memoria. Además, una llamada de función de miembro directo es (potencialmente) más rápida que una llamada de función de miembro virtual. No peses prematuramente a tu clase al hacer que las funciones de miembro sean virtuales de manera preventiva.

Si su código sigue un patrón de diseño particular, entonces su elección debe reflejar los propios principios del PD. Por ejemplo, si está codificando un patrón de Decorator , la función que debería ser virtual son las que pertenecen a la interfaz de componentes.

De lo contrario, me gustaría seguir un enfoque evolutivo, IOW, no tengo métodos virtuales hasta que veo que una jerarquía está tratando de emerger de su código.


Supongo que una forma posible de determinar rápidamente sería considerar si va a lidiar con un grupo de clases similares que va a usar para realizar las mismas tareas, y el cambio es la forma en que realiza esas tareas.

Un ejemplo trivial sería el problema de computar áreas para varias figuras geométricas. Necesita las áreas de cuadrados, círculos, rectángulos, triángulos, etc. y lo único que cambia aquí son las fórmulas matemáticas (la forma) que usa para calcular el área. Por lo tanto, sería una buena decisión hacer que cada una de estas formas se herede de una clase base común y agregar un método virtual en la clase base que devuelva el área (que luego puede implementar en cada uno de los niños con la fórmula matemática correspondiente) .

Hacer que todo sea virtual "por si acaso" hará que sus objetos ocupen más memoria. Además, hay una pequeña sobrecarga (pero no cero) al llamar a funciones virtuales. Así que, en mi humilde opinión, hacer que todo sea virtual "por si acaso" sería una mala idea cuando las limitaciones de rendimiento / memoria son importantes (lo que básicamente significa en cada programa del mundo real que escribes).

Sin embargo, esto también es discutible en función de la claridad con la que se detallan los requisitos y la frecuencia con la que se esperan cambios en el código. Por ejemplo, en una herramienta rápida y sucia o en un prototipo inicial donde unos pocos bytes extra de memoria y unos pocos milisegundos de tiempo perdido no significan mucho, estaría bien tener un montón de funciones virtuales (innecesariamente) por el bien de flexibilidad.


Una prueba de cordura que utilizo principalmente es: en caso de que una clase que estoy definiendo se derive en el futuro, ¿el comportamiento (función) seguirá siendo el mismo o debería ser redefinido? Si lo fuera, la función es un fuerte contendiente para ser virtual, si no, entonces no, si no lo sé; probablemente deba examinar el dominio del problema para comprender mejor el comportamiento que planeo implementar. En su mayoría, el dominio de problemas me da la respuesta, en los casos en que no, el comportamiento generalmente no es crítico.