15.6. ¿Por qué funciones virtuales?

A estas alturas usted se puede hacer una pregunta: «Si esta técnica es tan importante, y si se ejecuta la función correcta todo el tiempo, ¿por qué es una opción? ¿Por qué tengo siquiera que conocerla?»

Es una buena pregunta, y la respuesta forma parte de la filosofía fundamental de C++: «Porque no es igual de eficiente». Se puede ver en la salida en lenguaje ensamblador anterior que, en vez de un simple CALL a una dirección absoluta, se necesitan dos instrucciones de ensamblador, más sofisticadas, para preparar la llamada a la función virtual. Esto requiere más código y más tiempo de ejecución.

Algunos lenguajes orientados a objetos han adoptado el enfoque de que la ligadura dinámica es tan intrínseca a la programación orientada a objetos que siempre debe tener lugar, que no debe ser opcional, y que el usuario no tiene por qué conocerla. Ésta es una decisión de diseño cuando se crea un lenguaje, y ese camino concreto es adecuado para muchos lenguajes[81]. Sin embargo, C++ procede de la herencia de C, donde la eficiencia es crítica. Después de todo, C fue creado para sustituir al lenguaje ensamblador para la implementación de un sistema operativo (haciendo a este sistema operativo - Unix - mucho más portable que sus antecesores). Y una de las principales razones para la invención de C++ fue hacer más eficientes a los programadores de C[82]. Y la primera pregunta que se hacen los programadores de C cuando se encuentran con C++ es: «¿Cómo me afectará en tamaño y velocidad?» Si la respuesta fuera «Todo es magnífico excepto en las llamadas a funciones, donde siempre tendrá una pequeña sobrecarga extra», mucha gente seguiría con C en lugar de hacer el cambio a C++. Además las funciones inline no serían posibles, porque las funciones virtuales deben tener una dirección para meter en la VTABLE. Por lo tanto las funciones virtuales son opcionales, y por defecto el lenguaje no es virtual, porque es la configuración más rápida. Stroustrup expuso que su directriz era: «Si no lo usa, no lo paga».

Así pues, la palabra reservada virtual se proporciona para afinar la eficiencia. Cuando se diseñan las clases, sin embargo, no hay que preocuparse por afinar la eficiencia. Si va a usar el polimorfismo, use funciones virtuales en todas partes. Sólo es necesario buscar funciones que se puedan hacer no virtuales cuando se estén buscando modos de acelerar el código (y normalmente hay mucho más que ganar en otras áreas - un buen perfilador encontrará los cuellos de botella mucho mejor que usted intentando adivinarlos).

La experiencia práctica sugiere que el impacto en tamaño y velocidad de pasarse a C++ no supera el 10 por ciento con respecto al tamaño y la velocidad de C, y que a menudo ambos están mucho más cerca de ser parejos. La razón por la que se podría obtener una mayor eficiencia en tamaño y velocidad es que un programa en C++ se puede diseñar de una forma más pequeña y rápida de lo que se haría en C.



[81] Smalltalk, Java y Python, por ejemplo, usan este enfoque con gran éxito.

[82] En los laboratorios Bell, donde se inventó C++, hay un montón de programadores de C. Hacerlos a todos más eficientes, aunque sea sólo un poco, ahorra a la compañía muchos millones.