2010-11-10 15 views
6

Como novato programador de C++ siempre he puesto la interfaz de mis clases en archivos .h y la implementación en archivos .cpp. Sin embargo, recientemente probé C# por un tiempo y me gusta mucho su sintaxis clara y la forma de organizar los archivos, en particular, no hay diferencias entre los encabezados y la implementación; por lo general, implementa una clase para cada archivo .cs y no necesita encabezados.Usando encabezados C++ (.h) vs encabezados más implementación (.h + .cpp), ¿cuáles son las desventajas?

sé que en C++ esto también es posible (se puede codificar funciones "en línea" en .h archivos), pero hasta ahora siempre han visto una clara distinción entre .h y .cpp archivos en proyectos de C++. ¿Cuáles son las ventajas y desventajas de este enfoque?

Gracias

+1

posible duplicado de [código C++ en archivos de encabezado] (http://stackoverflow.com/questions/583255/c-code-in-header-files) –

Respuesta

9

Hay algunas maneras que separa los dos ayuda en C++. En primer lugar, si desea actualizar una biblioteca sin cambiar una interfaz, tener el código en el archivo C++ significa que simplemente puede actualizar la biblioteca en lugar de la biblioteca más los encabezados. En segundo lugar, oculta la implementación. Es decir, obliga a las personas a mirar su clase solo en términos de la interfaz, lo que debería preocuparlos si el código está bien escrito. Finalmente, hay una especie de limpieza estética con la interfaz + documentación que viene con esta separación. Es algo a lo que tiene que acostumbrarse, pero después de un tiempo se sentirá natural (opinión)

+2

El argumento "separar la interfaz de la implementación" es falso. Sí, el código bien escrito solo se refiere a la interfaz. Pero seamos sinceros, usar encabezados separados no obliga a nadie a escribir un buen código en este tema (a menos que bloquee la implementación, e incluso entonces alguien * podría * usar API no documentadas). Es como decir que Python fomenta el código legible al requerir algo de sangría. – delnan

+1

@delnan hay muy poco que se puede hacer para detener el código incorrecto que no sea la revisión de código. – wheaties

+0

Nah, este es un argumento falso. Esto también es posible en un lenguaje como C#. La característica clave es que la accesibilidad de clase se puede controlar a nivel de módulo, una característica que C++ no tiene. Debido a su modelo de compilación. –

1

La principal diferencia es que algo implementado dentro de un archivo .h se colocará en cada unidad de compilación que incluye esa cabecera, esto va a crear la redundancia durante la fase de compilación en el ejecutable binario final .. mientras se divide con .h y .cpp lo compilará en un solo archivo de objeto que luego se vinculará con los otros archivos de objetos al tener solo un código binario compilado que implemente ese archivo de encabezado.

Además si se declara cosas justo dentro de un .h no son capaces de compartir variables y estructuras entre otros más .cpp archivos ..

+0

El enlazador eliminará la redundancia, por lo que el ejecutable final no ser más grande Sin embargo, el tamaño combinado de todos los archivos de objetos será mayor. – Sjoerd

+0

Una forma de mitigar este problema es poner * todo * en archivos .h, y luego tener solo un compilable .cpp que los incluya a todos. (Esto no funcionará para una biblioteca, pero funcionará para un ejecutable). –

1

Es interesante observar que C# parece ir en la dirección C/C++ en cierta medida recientemente, con la introducción de clases parciales La ventaja particular de esto en el IDE es que el diseñador de Visual Studio modificará la parte de la clase que trata con controles visuales o miembros de datos y su diseño que residen en un archivo separado.

+1

Las clases parciales son * no * solo una separación de la implementación. Declaración también. No hay equivalente para él en C++. –

+1

Las clases parciales son invenciones de la imaginación del diseñador y solo existen para dividir las preocupaciones físicas de la codificación, como la separación del código generado por la herramienta. No existen más allá del punto de compilación de la misma manera que existen los archivos de encabezado. – Will

5

No olvides los tiempos de compilación.

Poner el código de implementación en archivos de encabezado los hace más propensos a ser cambiados. Y cambiar los archivos de encabezado provocará reconstrucciones de todos los archivos CPP que los incluyen, lo que a su vez aumenta los tiempos de compilación. Esto puede ser significativo en proyectos más grandes.

También soy seguidor de mantener oculta la implementación de los usuarios de mis bibliotecas. Lamentablemente, esto no funciona para las clases de plantilla.

Mi regla de oro: mantener las declaraciones en archivos .H, mantener las definiciones en archivos .CPP.

+0

great answer @dripfeed ¿Puede decirme por qué no vinculamos archivos .h como archivos .cpp en lugar de incluirlos? –

1

Me volvería a repetir @wheaties y añadir algunos elementos adicionales

  1. compilación es más fácil (puede ser sólo soy yo), que nunca he sido capaz de obtener la compilación de trabajar a la perfección si modifica el encabezado solamente (como en todos los archivos de implementación que lo han incluido). Creo que en Makefiles tienes que agregar manualmente las dependencias, lo que es un verdadero dolor en proyectos a gran escala (de nuevo podría ser solo yo). Entonces, si tienes tu código en los archivos de implementación, entonces los cambios simplemente significan recompilar ese archivo en particular, muy útil cuando quieres hacer cambios rápidos, construir y probar.

  2. Permítanme volver a iterar el aspecto de ocultación, la mayoría de las veces no quiere que la gente conozca los detalles de implementación debido a la naturaleza sensible del código y solo expone los encabezados más las bibliotecas pre compiladas, y la separación es clave aquí.

  3. Reenviar declaraciones, buen truco donde no es necesario incluir los detalles de implementación de una clase en el archivo de encabezado si no se está "utilizando" en ninguno de los códigos del encabezado, pero luego en el archivo de implementación puede incluir la cabecera real y "todo funciona muy bien" (ayuda si usted tiene dependencias cíclicas - por qué tiene de ellos es cuestión diferente)

0

veo que una gran cantidad de respuestas abogan por la separación, sobre todo para construir -tiempo e implementación que oculta los beneficios. Ambas son definitivamente ventajas, aunque argumentaré en el contraejemplo: Boost.

La mayoría de las bibliotecas de Boost utilizan un archivo .hpp sin enlaces externos. La razón es que esto se requiere a menudo en el caso de las plantillas, cuando el compilador debe conocer los tipos de argumentos de la rutina que realiza la llamada. Por lo tanto, es posible que no tenga otra opción si quiere seguir con el enfoque "moderno" de C++ para evitar las clases de plantillas.

+0

Las plantillas son una olla de pescado diferente. El OP fue, creo, refiriéndose a la práctica * en general * de poner la implementación en el archivo de encabezado. –

1

En un gran proyecto reciente, los autores de los sistemas que quería utilizar habían colocado una gran cantidad del código en archivos .h. Al incluir sus archivos .h en mi propia fuente, agregué más dependencias a mi archivo. Después de incluir las dependencias para su proyecto, terminé con colisiones typedef. Si hubieran separado el código y solo hubieran colocado declaraciones en el archivo .h, hubiera sido mucho más simple. Sugiero usar tipos de posix y solo poner declaraciones en archivos .h.

2

es mejor tener los símbolos definidos en un solo lugar para el caso que quería compilar C++ con los binarios ya compilados (normalmente cuando se usa una biblioteca). imagina que necesitas definir símbolos externos para cosas globales en tus binarios. si tuvieras el código .cpp y .h en el mismo archivo, deberías definir los símbolos de tus binarios para cada uno de esos archivos. en dos archivos, puede tener solo .h con definiciones de binarios y muchos archivos .cpp que lo usan.

0

En cuanto a la parte de comparación de .cs frente .cpp/.h Creo que hay que tener en cuenta los antecedentes del arquitecto principal de C#: Anders Hejlsberg. En Delphi tampoco tiene la distinción de encabezado y módulo (ignorando incluir archivos para esta discusión). Simplemente tiene dos secciones en un archivo de unidad initialization y implementation.

Los otros puntos ya fueron mencionados.

Cuestiones relacionadas