El almacenamiento automático es una forma de conservar memoria,
porque las variables automáticas existen sólo cuando
son necesitadas. Son creadas al introducirse la función en
la cual son declaradas, y son destruídas cuando se sale de
dicha función.
El especificador de clase de almacenamiento register puede ser colocado
a antes de una declaración de variable automática,
para sugerir que el compilador conserve la variable en uno de los
registros de alta velocidad del hardware de la computadora. Si se
pueden mantener en registros de hardware las variables intensamente
utilizadas como son contadores y totales, puede ser eliminada la
sobrecarga correspondiente a cargar de forma repetida las variables
de las memorias a los registros y almacenar los resultados de la
vuelta en memoria.
A menudo son inecesarias las declaraciones register. Los compiladores
optimizadores de hoy día son capaces de reconocer variables
de uso frecuente, y pueden decidir colocarlos en registro, sin necesidad
de una declaración register proveniente del programador.
Eviten programas recursivos del tipo fibonacci que resultan en una
"explosión" exponencial de llamadas.
Evite el uso de recursión cuando se requiera de rendimiento.
Las llamadas recursivas toman tiempo y consumen memoria adicional.
Un programa muy funcionalizado en comparación con un monolítico
(es decir, de una pieza) sin funciones potencialmente hace grandes
cantidades de llamadas de función y estas consumen tiempo
de ejecución en el procesador de una computadora. Pero los
programas monolíticos son difíciles de programar,
probar, depurar, mantener y de modificar.
El polimorfismo, tal y como se pone en práctica mediante
funciones virtuales y ligaduras dinámicas, resulta eficiente.
Los programadores pueden utilizar estas capacidades con un impacto
sólo nominal sobre el rendimiento del sistema.
Las funciones virtuales y las ligaduras dinámicas permiten
la programación polimórfica, en contraste con la programación
lógica switch. Los compiladores optimizantes de C++ por lo
general generan código que se ejecuta con una eficiencia
por lo menos igual a la de la lógica basada en switch codificada
manualmente.
Evite reinventar la rueda. Siempre que sea posible, utilice funciones
estandar de biblioteca ANSI C, en vez de escribir nuevas funciones.
Esto reduce el tiempo de desarrollo del programa.
En programas que contengan muchas funciones, main deber de
ser organizada como un grupo de llamadas a funciones que ejecuten
la mayor parte del trabajo del programa.
Cada función debería limitarse a ejecutar una tarea
sencilla y bien definida, y el nombre de la función debería
expresar dicha tarea con claridad. Ello facilitaría la abstracción
y promovería la reutilización del software.
Si no puede elegir un nombre conciso, que exprese lo que la función
ejecuta, es probable que su función está intentando
ejecutar demasiadas tareas diversas. A menudo es mejor dividir dicha
función en varias funciones más pequeñas.
Una función no debería tener una longitud mayor que
una página. Aún mejor una función no debería
ser más larga que media página. Las funciones pequeñas
promueven la reutilización del software.
Los programas deberían ser escritos como recompilaciones
de funciones pequeñas. Esto haría que los programas
fueran más fáciles de escribir, depurar, mantener
y modificar.
Una función que requiera un gran número de parámetros
quizás este ejecutando demasiadas tareas. Piense en dividir
esta función en funciones más pequeñas, que
ejecuten las tareas por separado. El encabezado de función,
si es posible, debería poder caber en una línea.
El prototipo de función, el encabezado de función
y las llamadas de función deberán todas estar de acuerdo
en lo que se refiere al número, tipo y el orden de argumentos
y de parámetros, así como en el tipo del valor de
regreso.
Un prototipo de función, colocado fuera de una definición
de función, se aplica a todas las llamadas de función
que aparezcan dentro del archivo después del prototipo de
función. Un prototipo de función colocado en una función,
se aplica sólo a las llamadas efectuadas en esa función.
El almacenamiento automático es otra vez un ejemplo del principio
del mínimo privilegio ¨por qué tendrían
que estar las variables almacenadas en memoria y accesibles cunado
de hecho no son necesarias?
La declaración de una variable como global en vez de como
local, permiten que ocurran efectos colaterales no deseados cuando
una función que no requiere el acceso a la variable, la modifica
accidental o maliciosamente. En general, el uso de las variables
globales debería ser evitado, excepto en cierta situaciones,
con requerimientos de rendimiento único.
Cualquier problema que puede ser resuelto en forma recursiva, también
puede ser resuelto de forma iterativa (no recursiva). Por lo general
se recoge un enfoque recursivo en preferencia a uno iterativo cuando
el enfoque recursivo es más natural al problema y resulta
en un programa que sea fácil de comprender y de depurar.
Otra razón para seleccionar una solución recursiva,
es que la solución iterativa pudiera no resultar aparente.
La funcionalización de los programas de una forma nítida
y jerárquica promueve buena ingeniería del software.
Una consecuencia interesante del uso de funciones virtuales y polimorfismo
es que los programas adquieren una apariencia simplificada. Contienen
menos lógica de bifurcación, prefiriendo un código
secuencial más sencillo. Esta simplificación facilita
probar, depurar y mantener el programa.
Una vez declarada una función como virtual, se conserva como
virtual a lo largo de toda la jerarquía de herencia a partir
de dicho punto.
Cuando una clase derivada decide no definir una función virtual,
la clase derivada heredar la función virtual de la
clase base inmediata.
La funciones virtuales redefinidas deben tener el mismo tipo de
regreso y la misma signatura que la función virtual base.
Si una clase se deriva de una clase con una función virtual
pura, y para dicha función virtual pura no se ha dado definición
en la clase derivada, entonces la función virtual también
se conserva pura en la clase derivada. Por consecuencia, también
la clase derivada ser una clase abstracta.
Mediante las funciones virtuales y el polimorfismo, el programador
puede ocuparse de generalidades y dejar que en tiempo de ejecución,
el entorno se preocupe de lo específico. El programador puede
dirigir una amplia variedad de objetos haciendo que se comporten
de formas apropiadas a dichos objetos incluso sin conocer los tipos
de los mismos.
|