5.1 Nomenclatura de las funciones
Los nombres de las funciones tienen que ser autoexplicativos. Tienen que dar una idea clara de cual es
su finalidad.
Los nombres de las funciones deberían empezar por una letra minúscula (por contra los
métodos de las clases tienen que empezar por una letra mayúscula).
Así seguimos una nomenclatura ampliamente difundida y utilizada.
De manera que sería poco correcto llamar a una función:
// Definición poco correcta de una función
int RealizarCopia (char *psDestino, char *psOrigen);
|
Mientras que sería correcto llamarla:
// Definición correcta de una función
int realizarCopia (char *psDestino, char *psOrigen);
|
Para componer los nombres de las funciones se aconseja utilizar formas verbales (infinitivos) pudiéndose
acompañar (o no) con sustantivos para precisar la acción.
De esta manera mejoramos la identificación de los distintos componentes de un sistema.
Por ejemplo, una función que hace una carga de datos en un array si la llamamos datos() no queda clara
su finalidad, en cambio si la llamamos cargarDatosIniciales() está muy claro su uso.
[subir]
5.2 Utilización de funciones
[subir]
5.3 Argumentos de las funciones
Los primeros argumentos deberían ser los argumentos de salida (o destino) y los últimos argumentos
los de entrada (u origen).
Así seguiríamos la forma de las funciones standard habituales, como memcpy, strcat, etc...
Además es raro que un argumento de salida sea un argumento opcional, normalmente los argumentos opcionales
son los argumentos de entrada.
Una definición de ejemplo:
// Función de copia, pon un argumento origen (psOrigen) y otro destino (psDestino)
int realizarCopia (char *psDestino, char *psOrigen);
|
Esta regla también se aplicará a los métodos de las clases C++.
Se debe comprobar la validez de los argumentos de entrada (tanto en las funciones como en los métodos) de la función siempre que puedan tomar valores
anómalos o inadecuados.
De esta manera evitaríamos posibles errores de funcionamiento debido a valores inesperados de argumentos de
entrada (por ejemplo si no han sido debidamente inicializados).
Se deben especificar los nombres de los argumentos formales de las funciones (y los métodos de las clases C++) en la definición de las mismas.
Esta suele ser una practica habitual, que ayuda a la legibilidad del código y reduce el riesgo de que cambios
en el código afecten a argumentos distintos de los que pensábamos.
Por ejemplo, el siguiente código:
// Definición poco correcta de miFuncion
void miFuncion (*pdDatoFinal, dDatoMinimo, dDatoMaximo, nIntervalo)
double *pdDatoFinal;
double dDatoMinimo;
double dDatoMaximo;
int nIntervalo;
{ ... }
|
Debería ser (para ser más correcto):
// Definición correcta de miFuncion.
void miFuncion (double *pdDatoFinal, double dDatoMinimo, double dDatoMaximo, int nIntervalo)
{ ... }
|
Sería aconsejable que las funciones (a los métodos C++ les pasaría lo mismo) no tuvieran un número grande de
argumentos (preferentemente menos de 7).
Cuantos más argumentos tenga una función es más probable que se pueda hacer un uso equivocado de la
función, al igual que se incrementa la dificultad de la lectura.
En general es aconsejable minimizar el uso de argumentos por defecto (tanto en las funciones como en los
métodos de las clases C++), o no usarlos, en especial en las
funciones sobrecargadas, para favorecer la comprensión del código.
En algunas ocasiones, al revisar el código se puede tener la duda de si algún argumento ha sido omitido
por error o intencionadamente, este error se agrava en funciones sobrecargadas, pudiendo dar lugar a
indeterminaciones.
En la definición de las funciones se aconseja poner en lineas separadas los argumentos de la
función, sobre todo si son muchos estos argumentos.
Por ejemplo:
// La siguiente definición de "miFuncion" sería más correcta que la anterior:
void miFuncion (double *pdDatoFinal,
double dDatoMinimo,
double dDatoMaximo,
int nIntervalo)
{ ... }
|
[subir]
5.4 Retorno de la función
Muy habitualmente el retorno de las funciones es un indicador de estado.
Hay que aconstumbrarse a comprobar siempre el estado devuelto por una función antes de continuar la ejecución
normal del programa.
Incluso es deseable que exista un registro de condiciones anómalas o inesperadas que recojan posibles errores
obtenidos mediante ese indicador de estado.
Esta regla también se aplicará tanto a las funciones como a los métodos de las clases C++.
Cuando una función (o un método de una clase C++) devuelva un indicador de estado, este indicador debe tomar un valor de los posibles que se encontrarán
en un fichero include designado a tal caso.
De esta manera se puede localizar claramente el motivo del error, si es que se produce alguno.
Una función no devolverá nunca un puntero a una variable local. Ya que la memoria
donde se guardan los calores las variables locales de las funciones es "desalocada" al salir de la función. El compilador
puede o no avisar de este problema.
[subir]
5.5 Referencias (C++)
En general debería limitarse (tanto en las funciones como en los métodos) mucho el uso de referencias (no constantes).
Si deben usarse referencias constantes en vez de llamadas por valor.
Con referencias se economiza el uso de la pila (y mejor si son constantes, ya que su uso tiene la misma síntaxis
que si fueran por valor), excepto para tipos predefinidos por el compilador (por que no se gana nada) y punteros
(por que no tiene sentido).
Al usar referencias en una función (o en un método C++) se puede modificar el contenido
del objeto referenciado, este caso que puede ser fuente de errores, se soluciona al pasar una
referencia constante a la función.
Las siguientes serían definiciones erroneas:
void maximoValor (CDato const &rObjeto); // error de codificación
void maximoValor (CDato const objeto); // pasa el objeto por valor
|
La forma correcta de definir esta función sería:
void maximoValor (const CDato &rObjeto); // uso correcto de referencias
|
[subir]
5.6 Sobrecarga de funciones (C++)
La sobrecarga de funciones (y métodos) debe utilizarse con mucho cuidado y de forma uniforme.
Se recomienda limitar su uso a operaciones definidas en el ámbito del problema, para mejorar
la claridad del código y su facilidad de comprensión.
Las funciones (y métodos) sobrecargadas tienen que estar muy relacionadas entre sí. Sería absurdo
que las función sobrecargadas tuvieran usos diferentes.
[subir]
5.7 Funciones inline
Solo se deberían utilizar funciones (y/o métodos) inline en las implementaciones (en el desarrollo de las funciones
miembro específicas que constituyen la lógica de funcionamiento de la clase (C++)).
Normalmente las funciones (y métodos) inline tendrían que declararse en un fichero aparte.
Esto se hace así para poder solucionar los problemas de algunos debugger con estas funciones.
Declarándolas en un fichero aparte, podemos incluir este fichero bien en el fichero de cabecera,
bien en el fichero de código, de acuerdo a nuestro interés.
Es preferible usar funciones (o métodos) inline en lugar de macros creadas utilizando #define.
Las funciones (y métodos) inline han de tener una sóla línea de código.
[subir]
5.8 Cabeceras de las funciones
[subir]
|