Manual de estilo C / C++

[< anterior]       [indice]       [siguiente >]

5. Funciones


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

  • En general se aconseja limitar el máximo posible la visibilidad de las funciones. Como norma general de protección de datos.

[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

  • Las definiciones de todas las funciones tienen que incluir una cabecera descriptiva que indique los siguientes campos.

    1. Nombre de la función.
    2. Finalidad o uso de la función.
    3. Argumentos de la función, indicando si son de entrada o salida, y la finalidad o uso de cada uno de ellos.
    4. Retorno de la función. Indicando los posibles valores de retorno y el significado de los mismos.
    5. Variables globales afectadas (si las hay).
    6. Nombre del autor y fecha de última modificación.
    7. Historial de moficiaciones, con fecha, motivo y nombre del autor.

[subir]


[< anterior]       [indice]       [siguiente >] Oscar Valtueña García - "Manual de estilo C / C++"