2012-03-12 7 views
12

Me acaba de pasar a la declaración en el título. La cita completa es:"Como regla general, convierta todos sus métodos en virtuales" en C++: ¿consejo de sonido?

Como regla general, hacen todas sus métodos virtuales (incluyendo el destructor, pero no de constructores) para evitar los problemas asociados con omisión de la palabra clave virtual.

He encontrado esto en el libro de Wrox Profesional C++. You can google it to check.

¿Hay algo que hacer? Hubiera pensado que solo proporcionaría puntos de extensión seleccionados, no por defecto, extensibilidad. Por ejemplo, a 2001 article by Herb Sutter says so. ¿Ha cambiado algo dramáticamente desde entonces para hacer lo opuesto a la norma imperante? (Tenga en cuenta que soy un novato en C++ por lo que no he estado siguiendo la discusión durante la última década.)

+2

He oído esto algunas veces pero nadie ha sido capaz de convencerme de seguirlo. Me parece un poco endeble. Tiendo a estar de acuerdo con tu análisis. Por supuesto, solo será altamente subjetivo. –

+1

¿La inclusión de la primera función virtual en una clase no complica la representación interna al forzar un vtable o algo así? Pensé que era 'Solo hazlo virtual cuando realmente tengas que hacerlo'. –

+1

... a menos que estés diseñando un juego. – Marlon

Respuesta

10

¿Hay algo a ella?

El consejo es BAD, no hay dudas al respecto. Leer algo así sería suficiente para mantenerse alejado del libro y su autor.

Verá, la palabra clave virtual indica "puede o debe anular este método, fue diseñado para esto".

Para cualquier tarea no trivial, no puedo imaginar un sistema razonable de clases que permita al usuario (es decir, a otro programador) anular todos y cada uno de los métodos en todas las clases derivadas. Es normal tener una clase abstracta base con solo métodos virtuales. Sin embargo, una vez que comienzas a crear clases derivadas, no hay razón para aplicar "virtual" en todo: algunos métodos no necesitan ser extensibles.

Convertir todo en virtual significa que en cualquier punto de código, sin importar el método que se llame, nunca se puede estar seguro de que la clase hará lo que se desea, porque alguien podría haber anulado su método, rompiéndolo en el proceso (De acuerdo con la Ley de Murphy, sucederá). Esto hará que su código no sea confiable y difícil de mantener. Otra cosa muy interesante es la forma en que se llaman los métodos virtuales en los constructores. Básicamente, siguiendo este consejo sacrifica la legibilidad/confiabilidad del código a cambio de no hacer un error tipográfico bastante raro. En mi opinión, no vale la pena.

En comparación, el método no virtual garantiza que pase lo que pase, en este punto del código, el código siempre funcionará como espera (sin contar los errores que aún no ha descubierto). Es decir. alguien más no reemplazará su método con alternativas rotas.

El consejo me recuerda un error común que algunos programadores novatos tienden a hacer: en lugar de desarrollar una solución sencilla que va a arreglar el problema, se distraen y tratar de hacer que el código universal y extensible. Como resultado, el proyecto tarda más en finalizar o nunca se completa, porque la solución universal para cada escenario posible requiere más esfuerzo/tiempo de desarrollo que una solución localizada que se limita solo al problema actual.

En lugar de seguir este consejo "virtual", recomendaría seguir con Murphy's Law y KISS principle. Funcionaron bien para . Sin embargo, no se garantiza que funcionen bien para todos los demás.

+0

Gracias, @SigTerm. Permítanme decir que el libro en cuestión, edición de 2011, actualizado para C++ 11, me pareció una introducción muy útil al idioma. Estoy leyendo lentamente, y varias fuentes en paralelo para hacer las cosas realmente claras para mí, y ya estaba preparado para la extensibilidad por defecto como en Java. Entonces este consejo me sorprendió. - Usted dice: "Otra cosa muy interesante es la forma en que se llaman los métodos virtuales en los constructores". [Google buscó este] (http://www.google.com?q=virtual+method+in+constructor); Parece que debería evitar llamar a métodos virtuales en ctors. – Lumi

0

No puede doler. Si no tiene una subclase que redefine la función, nada es diferente. Puedo ver que esta técnica es útil si tienes mucha herencia y puedes perder la pista de qué clases heredan.

Personalmente, no hago que todos los métodos de clase sean virtuales ... pero así soy yo. Tener todo virtual parece hacer que las cosas se vean más confusas, ¿eh?

+2

Puede doler. Tener> 0 funciones virtuales aumenta el tamaño del objeto. Puede oscurecer potencialmente al autor La intención Puede evitar potencialmente que el compilador inline. –

+0

El otro idioma que uso con frecuencia (Python) hace que todas las funciones sean virtuales por defecto (no hay palabra clave). Por lo tanto, usar este enfoque no puede ser tan malo. – austin1howard

+0

Veo lo que quiere decir @OliCharlesworth ... Solo decía que el código aún funcionaría correctamente. Pero estuvo de acuerdo ... no es el enfoque más eficiente. – austin1howard

11

No estoy de acuerdo con el principio.

En el pasado, algunos estaban preocupados por el uso excesivo de virtual debido a problemas de rendimiento. Esto sigue siendo algo válido, pero no excesivamente problemático en el hardware actual. (Tenga en cuenta que la mayoría de los otros idiomas incurren en penalizaciones similares en estos días. Por ejemplo, el iPhone 2G de 400MHz usó el Objetivo C que incurre en una llamada a método virtual en cada llamada de función.)

Creo que solo debe usar virtual en métodos donde parece útil y razonable querer anularlo en una subclase. Para mí, sirve como una pista para otros programadores (o para su yo futuro) ya que "este es un lugar donde las subclases pueden personalizar sensiblemente el comportamiento". Si reemplazar el método en una subclase sería confuso o extraño de implementar, no use virtual.

Además, para las incubadoras y captadores simple, es probablemente una mala idea, ya que inhibirá procesos en línea.

-1

En mi humilde opinión, esta es una buena regla general para principiantes con C++. No es realmente dañino, excepto en escenarios muy específicos (los que enfrentan los programadores que saben exactamente cuáles son las compensaciones de la palabra clave virtual), y es una cosa menos en qué pensar.

Sin embargo, como toda regla general, se simplifica demasiado la situación, y cuando uno piensa cómo comunicarse con otros programadores qué métodos pueden o no ser buenos candidatos para la redefinición, uno ha superado la regla general.

2

Habrá una pequeña pérdida de rendimiento y algunos bytes de memoria desperdiciados.

El verdadero problema es que hace que el código sea menos fácil de mantener, ya que está diciendo algo acerca de la función que no es cierto. Podría causar mucha confusión.

Cuestiones relacionadas