¿Qué hacer si odio los archivos de encabezado C ++?

25

Siempre estaba confundido acerca de los archivos de encabezado. Son muy extraños: incluye un archivo .h que no incluye .cpp pero .cpp también se compila de alguna manera.

Recientemente me uní a un proyecto de equipo y, por supuesto, se utilizan .h y .cpp.
Entiendo que esto es muy importante, pero no puedo vivir con copiar y pegar cada declaración de función en cada una de las múltiples clases que tenemos.

¿Cómo manejo la convención de 2 archivos de manera eficiente?
¿Hay alguna herramienta para ayudar con eso, o cambiar automáticamente un archivo que se ve como ejemplo a continuación a .h y .cpp? (específicamente para MS VC ++ 2010)

class A
{
...
    Type f(Type a,Type b)
    {
        //implementation here, not in another file!
    }
...
};

Type f(Type a)
{
     //implementation here
}
...
Oleh Prypin
fuente
8
Esta pregunta podría ser de varias maneras ... "¿Por qué necesitamos encabezados cuando usamos c ++" o "¿Crees que un lenguaje moderno que debe compilarse debería usar encabezados?" Tal como está, tiene "¿Qué hago?" Y "odio" en el título, lo que desencadena una gran cantidad de banderas.
Tim Post
44
Su pregunta hace que parezca que no comprende C ++, o cómo lo compila el sistema que utilice. Aprenda a usarlo correctamente y luego haga preguntas más subjetivas.
David Thornley
31
Su primera oración indica que no "comprende todo sobre los encabezados". La inclusión de un archivo .h no hace que el archivo .cpp correspondiente se "compile de alguna manera también". Compila archivos .cpp de forma independiente por derecho propio. Si no ha compilado el correspondiente .cpp, la inclusión de un encabezado sin un archivo de objeto correspondiente hará que falle el enlazador.
Paul Butcher
55
¿Qué hacer? Encuentra otro idioma si te molesta tanto.
Paul Nathan
55
Acerca de "no se puede vivir con copiar y pegar": cada vez que se actualiza una función, hay que actualizar todos los lugares donde se llama de todos modos. Como las personas que llaman son mucho más difíciles de encontrar que la declaración en el archivo de encabezado, actualizar el encabezado es solo un detalle menor.
Sjoerd

Respuestas:

15

Escribir más refactorización amigable C ++

En C ++ no tiene que usar encabezados en absoluto. Puede definir todo el objeto en un archivo tal como lo haría con C # o Java. Los desarrolladores de C generalmente solo mantendrán llamadas externas en un archivo de encabezado. Todas las llamadas internas se definirían en el archivo .c. Del mismo modo, puede reservar sus archivos C ++ .h para las clases / interfaces (clases abstractas virtuales puras) / etc. que están destinados a ser compartidos fuera de la DLL. Para clases / estructuras / interfaces internas, etc., simplemente incluiría el archivo .cpp que necesita:

#include<myclass.cpp>

Este no parece ser el enfoque más popular, pero es legal C ++. Definitivamente sería una posibilidad para todo su código interno. Esto permite que el código interno y el conjunto de clases cambien mucho más radicalmente al tiempo que proporciona una interfaz más estable para que el código fuera de su biblioteca / ejecutable interactúe.

Tener toda tu clase dentro de un archivo hará que sea más fácil hacer lo que quieras. No resolverá el problema de renombrar un método y tener que buscar en cada lugar donde se llame ese método, pero se asegurará de que tenga más mensajes de error inteligibles. Nada peor que hacer que su encabezado declare un método de una manera, pero lo implementa de manera diferente. Otro código que llama al archivo de encabezado se compilará correctamente y obtendrá una excepción de enlace, mientras que el archivo de implementación será el que se queje de que el método no se definió. Cuando defina cada método en su lugar (en la declaración de clase real), obtendrá el mismo mensaje de error sin importar qué archivo lo incluya.

También puede consultar esta pregunta: buenas herramientas de refactorización para C ++

Cómo C / C ++ resuelve los archivos de encabezado / implementación

En el nivel base C (y C ++ se basa en esa base), los archivos de encabezado declaran la promesa de una función / estructura / variable que es suficiente para permitir que un compilador cree el archivo objeto. De manera similar, los archivos de encabezado de C ++ declaran la promesa de funciones, estructuras, clases, etc. Es esta definición la que utiliza el compilador para reservar espacio en la pila, etc.

Los archivos .c o .cpp tienen la implementación. A medida que el compilador convierte cada archivo de implementación en un archivo de objeto, hay ganchos para los conceptos no implementados (lo que se declaró en el encabezado). El vinculador vincula los ganchos a las implementaciones en otros archivos de objetos y crea un binario más grande que incluye todo el código (biblioteca compartida o ejecutable).

VS específico

En cuanto a trabajar con aquellos en Visual Studio, hay algunos asistentes que ayudan a facilitar un poco las cosas. El nuevo asistente de clase creará su par coincidente de encabezado y archivos de implementación. Incluso hay una función de navegador de clase que le permitirá declarar nuevos métodos. Inyectará la definición en el encabezado y el código auxiliar de implementación en el archivo .cpp. Visual Studio ha tenido esas características durante más de una década (siempre que las haya usado).

Berin Loritsch
fuente
El problema es que estoy en gran medida la modificación de las clases todo el tiempo, no sólo la adición de nuevas funciones, etc
Oleh Prypin
55
@BlaXpirit: Entonces, ¿por qué estás modificando tanto las clases todo el tiempo? Una de las ideas detrás del diseño OO es tener muchos bloques de construcción bastante estables. Si modificara mucho las clases, me gustaría un lenguaje más dinámico, como Common Lisp o Python.
David Thornley
2
Eso es lo que estoy haciendo. Estoy mejorando / modificando los "bloques de construcción" y agregando otros nuevos
Oleh Prypin
C ++ nunca ha sido refactorizado amigable. El concepto de refactorización no ganó impulso hasta que hubo herramientas que lo hicieron realmente fácil de hacer en IDE de Java. NOTA: esas características estaban allí para los desarrolladores de Smalltalk y otros idiomas, pero no se convirtió en la corriente principal hasta que estuvo disponible para mucha gente. Hasta ahora, aún no he visto a alguien implementarlo de manera inteligente para C ++. Quizás Resharper de JetBrains? Sé que tiene código C # y VB, pero no estoy seguro de si te dará una refactorización de C ++.
Berin Loritsch
@Berin: Fui a buscar herramientas de refactorización de C ++ hace un año o dos, y encontré dos cosas. Eran bastante caros en ese momento, y no vi versiones de prueba, así que no sé qué hicieron. Además, solo se trabajó con emacs, lo que limitaría su efectividad en una tienda de Visual Studio.
David Thornley
13

Conviértete en un desarrollador de Java.

Si realmente debe continuar desarrollando en C ++, puede intentar usar un IDE. A menudo ofrecen algún mecanismo por el cual puede agregar un método a una clase, y coloca automáticamente la declaración en el archivo .h y la definición en el archivo .cpp.

Carnicero paul
fuente
2
kthx, conozco un poco a Java, pero no puedes hacer DLL Win32 de bajo nivel con él, ¿verdad?
Oleh Prypin
41
No sé por qué, pero 'Convertirse en un desarrollador de Java' de alguna manera suena como un insulto: D.
Oliver Weiler
2
Si quieres hacer un nivel bajo, olvídate de los 'idiomas fáciles'. Bajo nivel cuesta sudor y lágrimas.
Batibix
55
No es una respuesta particularmente útil.
ChrisF
1
@OliverWeiler No percibo "convertirse en un desarrollador de Java" como un insulto. Programo tanto en C ++ como en Java, pero mi preferencia es Java porque es mucho más fácil sentarse y sacar el código que funciona (y más portátil). Si por alguna razón detesta la existencia de archivos de encabezado, probar Java puede ser la opción correcta (aunque es extraño que odie los archivos de encabezado; consideraría un cambio en IDE).
Trixie Wolf
7

Podrías estar interesado en los maquilladores programa de Hwaci (los que hacen SQLite y Fossil).

También eche un vistazo a cómo se construye el fósil para tener una idea.

Benoit
fuente
55
El autor de la pregunta todavía necesita comprender la relación entre .h y .cpp bastante bien.
Trabajo
2
Entiendo lo básico. La respuesta parece ser justo lo que necesito.
Oleh Prypin
4

Cuando escribe las primeras líneas de una nueva clase, generalmente es porque la necesita en un lugar solo en ese momento. En un momento posterior, podría usarse en más lugares, pero inicialmente generalmente no lo es.

Muchas de mis clases comienzan en la parte superior del archivo .cpp actual. Cuando se ha estabilizado lo suficiente como para usarlo en varios lugares, lo pego en un encabezado. Aunque a menudo la clase desaparece tan rápido como apareció.

Sjoerd
fuente
-1

Como sugerencia para ayudar a manejar los archivos de encabezado C ++, es común usarlos sin extensión de archivo o sufijo de archivo, como lo hacen las bibliotecas "GCC".

Si este es su caso, sugiero utilizar una extensión de archivo " .hpp" (o unleast " .hxx") o un sufijo de archivo.

Es posible que deba configurar su compilador, el entorno del desarrollador o el programa Build.

umlcat
fuente
3
¿Estás hablando de cómo cuando incluyes un archivo como #include <iostream>? Esos no son solo para la biblioteca GCC. De hecho, está definido en el estándar C ++ de 1997 , sección 17.3.1.2. Evitaría nombrar archivos como ese. Puede, pero la razón por la cual la biblioteca estándar de C ++ lo hizo fue probablemente para evitar conflictos de nombres. De hecho, me parece realmente extraño cuando los compiladores agregan automáticamente un '.h' cuando incluye un encabezado, me parece bastante poco estándar. Y nunca veo a nadie encabezados de nombre sin sufijo, excepto la biblioteca estándar de c ++.
vedosidad
1
Además, debo tener en cuenta que todos los compiladores que he usado, excepto Borland (que tanto odio), no agregan automáticamente un '.h' o '.hpp' o '.hxx' cuando intentas para incluir un archivo sin sufijo. No esperes #include <someclass>ser leído como #include <someclass.hpp>en todos los compiladores. Tu código se romperá.
vedosidad