vectores switch opciones hacer funciones estructuras con borland arreglos archivos c++ build-process compilation code-organization file-organization

c++ - switch - ¿Debo poner muchas funciones en un solo archivo? O, más o menos, una función por archivo?



menu de opciones con archivos y funciones c++ (9)

Para la parte HEADER, debe combinar elementos en agrupaciones lógicas y crear sus archivos HEADER basados ​​en eso. Esto parece y es muy lógico en mi humilde opinión.

Para la parte SOURCE, debe colocar cada implementación de función en un archivo SOURCE aparte. (las funciones estáticas son excepciones en este caso). Puede que esto no parezca lógico al principio, pero recuerde, un compilador conoce las funciones, pero un vinculador solo conoce los archivos o / obj y sus símbolos exportados. Esto puede cambiar considerablemente el tamaño del archivo de salida y este es un problema muy importante para los sistemas integrados.

Verifique glibc o el árbol de fuentes de CRT de Visual C ++ ...

Me encanta organizar mi código, así que, idealmente, quiero una clase por archivo o, cuando tengo funciones que no son miembros, una función por archivo.

Las razones son:

  1. Cuando leo el código siempre sabré en qué archivo debería encontrar una determinada función o clase.

  2. Si se trata de una función de una clase o una no miembro por archivo de encabezado, no incluiré un desorden cuando include un archivo de encabezado.

  3. Si realizo un pequeño cambio en una función, solo esa función tendrá que ser recompilada.

Sin embargo, dividir todo en muchos encabezados y muchos archivos de implementación puede reducir considerablemente la compilación. En mi proyecto, la mayoría de las funciones acceden a un cierto número de otras funciones de biblioteca con plantillas. Para que ese código se compile una y otra vez, una vez para cada archivo de implementación. La compilación de todo mi proyecto actualmente toma aproximadamente 45 minutos en una máquina. Hay aproximadamente 50 archivos de objeto, y cada uno usa los mismos encabezados de costos de compilación.

Quizás, ¿es aceptable tener una clase (o función no miembro) por archivo de encabezado , pero poner las implementaciones de muchas o todas estas funciones en un archivo de implementación, como en el siguiente ejemplo?

// foo.h void foo(int n); // bar.h void bar(double d); // foobar.cpp #include <vector> void foo(int n) { std::vector<int> v; ... } void bar(double d) { std::vector<int> w; ... }

Una vez más, la ventaja sería que puedo incluir solo la función foo o simplemente la función de barra, y la compilación de todo el proyecto será más rápida porque foobar.cpp es un archivo, por lo que std::vector<int> (que es solo un ejemplo aquí para alguna otra construcción con plantillas costosa para compilar) tiene que compilarse en una sola vez, en lugar de dos veces si compilé un foo.cpp y un bar.cpp separado. Por supuesto, mi razón (3) anterior no es válida para este escenario: después de simplemente cambiar foo () {...} tengo que recompilar el archivo completo, potencialmente grande, foobar.cpp .

¡Tengo curiosidad por tus opiniones!


Puede redeclarar algunas de sus funciones como métodos estáticos de una o más clases: esto le brinda la oportunidad (y una buena excusa) de agrupar varias de ellas en un único archivo fuente.

Una buena razón para tener o no tener varias funciones en un archivo fuente, si ese archivo fuente es uno a uno con archivos objeto, y el enlazador vincula archivos completos del objeto: si un ejecutable puede querer una función pero no otra, entonces ponga en archivos fuente separados (para que el vinculador pueda vincular uno sin el otro).


Puedo ver algunas ventajas en su enfoque, pero hay varias desventajas.

1) Incluir un paquete es una pesadilla. Puede terminar con 10-20 incluye para obtener las funciones que necesita. Por ejemplo, si STDIO o StdLib se implementaron de esta manera.

2) Buscar el código será un poco molesto, ya que, en general, es más fácil desplazarse por un archivo que cambiar de archivo. Obviamente, una gran cantidad de archivos es difícil, pero incluso con IDEs modernos, es bastante fácil colapsar el archivo hasta lo que necesita y muchos de ellos tienen listas de atajos de función.

3) hacer mantenimiento de archivos es un dolor.

4) Soy un gran fan de las funciones pequeñas y la refactorización. Cuando agrega sobrecarga (crea un nuevo archivo, lo agrega al control de fuente, ...), anima a las personas a escribir funciones más largas en las que, en lugar de dividir 1 función en 3 partes, solo crea 1 grande.


También traté de dividir archivos en una función por archivo, pero tenía algunos inconvenientes. A veces las funciones tienden a ser más grandes de lo que necesitan (no desea agregar un nuevo archivo c cada vez) a menos que sea diligente sobre la refacturación de su código (no lo soy). Actualmente pongo de 1 a 3 funciones en el archivo c y agrupo todos los archivos c para una funcionalidad en un directorio. Para los archivos de cabecera, tengo Funcionality.h Subfunctionality.h modo que pueda incluir todas las funciones a la vez cuando sea necesario o solo una pequeña función de utilidad si no se necesita todo el paquete.


Un antiguo profesor de programación mío sugirió dividir módulos cada cientos de líneas de código para su mantenimiento. Ya no desarrollo en C ++, pero en C # me limito a una clase por archivo, y el tamaño del archivo no importa siempre que no haya nada relacionado con mi objeto. Puede hacer uso de las regiones #pragma para reducir con gracia el espacio del editor, no está seguro de si el compilador C ++ las tiene, pero si lo hace, definitivamente, haga uso de ellas.

Si aún estuviera programando en C ++, agruparía las funciones por uso usando múltiples funciones por archivo. Así que puedo tener un archivo llamado ''Service.cpp'' con algunas funciones que definen ese "servicio". Tener una función por archivo a su vez causará que lamento encontrar su camino de regreso a su proyecto de alguna manera, de alguna manera.

Sin embargo, no es necesario tener varias miles de líneas de código por archivo. Las funciones en sí nunca deberían ser mucho más que unas pocas cientos de líneas de código como máximo. Recuerde siempre que una función solo debe hacer una cosa y mantenerse mínima. Si una función hace más de una cosa, debe refactorizarse en métodos auxiliares.

Nunca está de más tener varios archivos fuente que definan una sola entidad. Es decir: ''ServiceConnection.cpp'' ''ServiceSettings.cpp'', y así sucesivamente.

A veces, si hago un solo objeto y posee otros objetos, combinaré múltiples clases en un solo archivo. Por ejemplo, un control de botón que contiene objetos ''ButtonLink'', podría combinar eso en la clase Button. A veces no, pero esa es una decisión de "preferencia del momento".

Haz lo que funcione mejor para ti. Experimentar un poco con diferentes estilos en proyectos más pequeños puede ayudar. Espero que esto te ayude un poco.


Una función por archivo podría volverse desordenada en mi opinión. Imagine si los encabezados POSIX y ANSI C se hicieron de la misma manera.

#include <strlen.h> #include <strcpy.h> #include <strncpy.h> #include <strchr.h> #include <strstr.h> #include <malloc.h> #include <calloc.h> #include <free.h> #include <printf.h> #include <fprintf.h> #include <vpritnf.h> #include <snprintf.h>

Sin embargo, una clase por archivo es una buena idea.


Usamos el principio de una función externa por archivo. Sin embargo, dentro de este archivo puede haber varias otras funciones de "ayuda" en espacios de nombres sin nombre que se utilizan para implementar esa función.

En nuestra experiencia, contrariamente a algunos otros comentarios, esto ha tenido dos beneficios principales. El primero es que los tiempos de compilación son más rápidos ya que los módulos solo necesitan ser reconstruidos cuando se modifican sus API específicas. La segunda ventaja es que al usar un esquema de nombres común, nunca es necesario perder tiempo buscando el encabezado que contiene la función a la que desea llamar:

// getShapeColor.h Color getShapeColor (Shape); // getTextColor.h Color getTextColor (Text);

No estoy de acuerdo con que la biblioteca estándar sea un buen ejemplo para no usar una función (externa) por archivo. Las bibliotecas estándar nunca cambian y tienen interfaces bien definidas, por lo que ninguno de los puntos anteriores se aplica a ellas.

Dicho esto, incluso en el caso de la biblioteca estándar, existen algunos beneficios potenciales al dividir las funciones individuales. El primero es que los compiladores pueden generar una advertencia útil cuando se usan versiones inseguras de funciones, por ej. strcpy vs strncpy , de manera similar a cómo g ++ solía advertir para la inclusión de vs.

Otra ventaja es que ya no me sorprendería incluir memoria cuando quiero usar memmove .


En mi humilde opinión, debe combinar elementos en agrupaciones lógicas y crear sus archivos en función de eso.

Cuando estoy escribiendo funciones, a menudo hay media docena más o menos estrechamente relacionadas entre sí. Tiendo a juntarlos en un solo encabezado y archivo de implementación.

Cuando escribo clases, generalmente me limito a una clase de peso pesado por encabezado y archivo de implementación. Podría agregar algunas funciones de conveniencia o pequeñas clases de ayuda.

Si encuentro que un archivo de implementación tiene miles de líneas de longitud, eso suele ser una señal de que hay demasiado allí y necesito separarlo.


Una función por archivo tiene una ventaja técnica si está creando una biblioteca estática (que supongo que es una de las razones por las que proyectos como el proyecto Musl-libc siguen este patrón).

Las bibliotecas estáticas están vinculadas con la granularidad del archivo de objeto y, por lo tanto, si tiene una biblioteca estática libfoobar.a compuesta por *:

foo.o foo1 foo2 bar.o bar

luego, si vincula la lib para la función de la bar , el miembro del archivo bar.o se vinculará, pero no el miembro foo.o Si enlaza con foo1 , el miembro foo.o se vinculará, lo que foo2 función foo2 posiblemente innecesaria.

Posiblemente haya otras formas de evitar que las funciones innecesarias se vinculen en ( -ffunction-sections -fdata-sections y --gc-sections ) pero una función por archivo es probablemente la más confiable.

  • Estoy ignorando el cambio de nombre de C ++ aquí por el bien de la simplicidad