una que programacion otro incluir hacer ficheros crear como codigo cabecera archivos archivo c++ header code-separation

que - Archivos de encabezado C++, separación de código



incluir un archivo c en otro (5)

Soy nuevo en C ++ y tuve algunas preguntas generales sobre la separación de códigos. Actualmente, he creado una pequeña aplicación, todo en un solo archivo. Lo que quiero hacer ahora es convertir esto en archivos separados de manera que contengan un código similar o lo que sea. Mi verdadera pregunta en este momento es, ¿cómo sé cómo separar las cosas? ¿Cuál es el margen invisible en el que debe separarse el código?

Además, ¿cuál es el sentido de los archivos de encabezado? ¿Es para reenviar declarar métodos y clases para que pueda usarlos en mi código antes de que el vinculador los incluya durante la compilación?

Cualquier idea sobre los métodos o las mejores prácticas sería genial, ¡gracias!


Decidir cómo separar el código en diferentes clases / funciones es una de las tareas principales de la programación. Hay muchas pautas diferentes sobre cómo hacer esto y recomendaría leer algunos tutoriales sobre C ++ y Object Oriented Design para que comiences.

Algunas pautas básicas serán

  • Junte las cosas que se usan juntas
  • Crear clases para objetos de dominio (por ejemplo, archivos, colecciones, etc.)

Los archivos de encabezado le permiten declarar una clase o función y luego usarla en varios archivos fuente diferentes. Por ejemplo, si declaras una clase en un archivo de cabecera

// A.h class A { public: int fn(); };

A continuación, puede utilizar esta clase en varios archivos de origen:

// A.cpp #include "A.h" int A::fn() {/* implementation of fn */} //B.cpp #include "A.h" void OtherFunction() { A a; a.fn(); }

Por lo tanto, los archivos de cabecera le permiten separar la declaración de la implementación. Si tuviera que poner todo (declaración e implementación) en un archivo fuente (por ejemplo, A.cpp), intente incluirlo en un segundo archivo, por ejemplo

// B.cpp #include "A.cpp" //DON''T do this!

Luego podría compilar B.cpp pero cuando intente vincular su programa, el enlazador se quejará de que tiene objetos definidos múltiples, esto se debe a que tiene copias múltiples de la implementación de A.


En primer lugar, no debe poner nada en los encabezados que no sea necesario para ser visible por cualquier otro archivo, que no sea el que lo necesita. Entonces, definamos algo que necesitamos a continuación.

Unidad de traducción

Una Unidad de Traducción es el código actual que se está compilando, y todo el código incluido por él, directa o indirectamente. Una unidad de traducción se traduce a un archivo .o / .obj.

Programa

Esos son todos sus archivos .o / .obj vinculados en un solo archivo binario que se puede ejecutar para formar un proceso.

¿Cuáles son los puntos principales de tener diferentes unidades de traducción?

  1. Reduzca las dependencias, de modo que si cambia un método de una clase, no tiene que volver a compilar todo el código de su programa, sino solo la unidad de traducción afectada. Un
  2. Reduzca los posibles conflictos de nombres al tener los nombres locales de la unidad de traducción, que no son visibles para otra unidad de traducción cuando los une.

Ahora, ¿cómo puedes dividir tu código en diferentes unidades de traducción? La respuesta es que no hay "¡así lo haces!", Pero debes considerarla caso por caso. A menudo es claro, ya que tiene diferentes clases, que pueden y deben colocarse en diferentes unidades de traducción:

foo.hpp:

/* Only declaration of class foo we define below. Note that a declaration * is not a definition. But a definition is always also a declaration */ class foo; /* definition of a class foo. the same class definition can appear in multiple translation units provided that each definition is the same basicially, but only once per translation unit. This too is called the "One Definition Rule" (ODR). */ class foo { /* declaration of a member function doit */ void doit(); /* definition of an data-member age */ int age; };

Declara algunas funciones y objetos gratis:

/* if you have translation unit non-local (with so-called extern linkage) names, you declare them here, so other translation units can include your file "foo.hpp" and use them. */ void getTheAnswer(); /* to avoid that the following is a definition of a object, you put "extern" in front of it. */ extern int answerCheat;

foo.cpp:

/* include the header of it */ #include "foo.hpp" /* definition of the member function doit */ void foo::doit() { /* ... */ } /* definition of a translation unit local name. preferred way in c++. */ namespace { void help() { /* ... */ } } void getTheAnswer() { /* let''s call our helper function */ help(); /* ... */ } /* define answerCheat. non-const objects are translation unit nonlocal by default */ int answerCheat = 42;

bar.hpp:

/* so, this is the same as above, just with other classes/files... */ class bar { public: bar(); /* constructor */ };

bar.cpp:

/* we need the foo.hpp file, which declares getTheAnswer() */ #include "foo.hpp" #include "bar.hpp" bar::bar() { /* make use of getTheAnswer() */ getTheAnswer(); }

Tenga en cuenta que los nombres dentro de un espacio de nombre anónimo (como el anterior) no chocan, ya que parecen ser unidad de traducción local. en realidad no lo son, solo tienen nombres únicos para que no choquen. si realmente desea (hay pocas razones para) nombres locales de la unidad de traducción (por ejemplo, debido a la compatibilidad con c para que el código C pueda llamar a su función), puede hacerlo así:

static void help() { /* .... */ }

El ODR también dice que no puede tener más de una definición de cualquier objeto o función no en línea en un programa (las clases son tipos, no objetos, por lo que no se aplica a ellas). Por lo tanto, debe tener cuidado de no colocar funciones que no sean en línea en los encabezados, o de no poner objetos como "int foo"; en encabezados. Eso causará errores del enlazador cuando el enlazador intente vincular las unidades de traducción, incluidos esos encabezados, entre sí.

Espero poder ayudarte un poco. Ahora que fue una respuesta larga, de hecho hay errores en alguna parte. Sé que una unidad de traducción estrictamente se define de otra manera (salida del pre-procesador). Pero creo que no agregaría un gran valor incluir eso en lo anterior, y confundiría el asunto. Por favor, siéntete libre de abofetearme si encuentras errores reales :)


Los archivos de encabezado deben contener declaraciones de clases y funciones.

Los archivos de origen contienen definiciones de clases y funciones.

Es una práctica estándar (es decir, más fácil leer) tener una declaración por archivo de encabezado y una definición por archivo de origen, aunque para objetos pequeños (ayuda más simple) a veces los agrupa con objetos más sustanciales relacionados.

Ejemplo: Menú de clase

Menu.h: Contains the Menu declaration. Menu.cpp: Contains the Menu definition.

El motivo por el que los archivos de encabezado contienen las declaraciones es para que pueda incluirlos desde múltiples archivos de origen y, por lo tanto, cada archivo fuente tiene exactamente la misma definición de cada clase y función.

Considéralo de esta manera:
Si no tenía archivos de encabezado, entonces necesitaría tener las definiciones de clase y / o declaraciones de función (sin) en cada archivo fuente, esto significa una copia de la misma declaración en cada archivo. Por lo tanto, si modifica una clase, debe hacer la misma modificación en cada archivo. Mediante el uso de un archivo de cabecera, tiene la declaración en un solo lugar y, por lo tanto, solo un objeto para modificar.


Sugerencia: 1. Tenga listo un diseño para su aplicación ahora. 2. Basado en el diseño, crea los objetos necesarios que interactúan entre sí. 3. Refactorice o cambie completamente el código existente para adaptarlo al diseño recién creado.

Los archivos de encabezado proporcionan una interfaz para las otras clases que pueden usar su funcionalidad.