He visto que hay varios paradigmas diferentes en C ++ con respecto a lo que entra en el archivo de encabezado y qué al archivo cpp. AFAIK, la mayoría de las personas, especialmente aquellas con antecedentes en C, hacen:
foo.h
class foo {
private:
int mem;
int bar();
public:
foo();
foo(const foo&);
foo& operator=(foo);
~foo();
}
foo.cpp
#include foo.h
foo::bar() { return mem; }
foo::foo() { mem = 42; }
foo::foo(const foo& f) { mem = f.mem; }
foo::operator=(foo f) { mem = f.mem; }
foo::~foo() {}
int main(int argc, char *argv[]) { foo f; }
Sin embargo, mis profesores suelen enseñar C ++ a principiantes como este:
foo.h
class foo {
private:
int mem;
int bar() { return mem; }
public:
foo() { mem = 42; }
foo(const foo& f) { mem = f.mem; }
foo& operator=(foo f) { mem = f.mem; }
~foo() {}
}
foo.cpp
#include foo.h
int main(int argc, char* argv[]) { foo f; }
// other global helper functions, DLL exports, and whatnot
Originario de Java, también siempre me he adherido a esta segunda vía por varias razones, como que solo tengo que cambiar algo en un lugar si cambian los nombres de la interfaz o del método, que me gusta la sangría diferente de las cosas en las clases cuando miro su implementación, y creo que los nombres son más legibles en foo
comparación con foo::foo
.
Quiero recolectar ventajas y desventajas de cualquier manera. ¿Quizás hay aún otras formas?
Una desventaja de mi manera es, por supuesto, la necesidad de declaraciones anticipadas ocasionales.
fuente
foo.cpp
ahora no tiene nada que ver con sufoo
clase y debe dejarse vacío (tal vez#include
para que su sistema de compilación sea feliz).Respuestas:
Si bien la segunda versión es más fácil de escribir, está mezclando la interfaz con la implementación.
Los archivos de origen que incluyen archivos de encabezado deben volver a compilarse cada vez que se cambian los archivos de encabezado. En la primera versión, cambiaría el archivo de encabezado solo si necesita cambiar la interfaz. En la segunda versión, cambiaría el archivo de encabezado si necesita cambiar la interfaz o la implementación.
Además de que no debe exponer detalles de implementación , obtendrá una compilación innecesaria con la segunda versión.
fuente
Lo hice por segunda vez en el '93-95. Tomó unos minutos para recompilar una pequeña aplicación con 5-10 funciones / archivos (en esa misma PC 486 ... y no, tampoco sabía nada de clases, solo tenía 14-15 años y no había Internet ) .
Entonces, lo que enseñas a los principiantes y lo que usas profesionalmente son técnicas muy diferentes, especialmente en C ++.
Creo que la comparación entre C ++ y un auto F1 es adecuada. No pones principiantes en un auto de F1 (que ni siquiera arranca a menos que precaliente el motor a 80-95 grados centígrados).
No enseñe C ++ como primer idioma. Debe tener la experiencia suficiente para saber por qué la opción 2 es peor que la opción 1 en general, saber un poco lo que significa la compilación / vinculación estática y, por lo tanto, comprender por qué C ++ lo prefiere de la primera manera.
fuente
El segundo método es lo que yo llamaría una clase totalmente en línea. Está escribiendo una definición de clase, pero todo el código que la use solo incluirá el código.
Sí, el compilador decide cuándo en línea y cuándo no ... Sin embargo, en este caso está ayudando al compilador a tomar una decisión, y potencialmente terminará generando menos código y potencialmente más rápido.
Es probable que esta ventaja supere el hecho de que si modifica la implementación de una función, necesita reconstruir toda la fuente que la utiliza. En la naturaleza ligera de la clase, no modificará la implementación. Si agrega un nuevo método, tendría que modificar el encabezado de todos modos.
Sin embargo, a medida que su clase se vuelve más compleja, incluso agregando un ciclo, el beneficio de hacerlo de esta manera disminuye.
Todavía tiene sus ventajas, en particular:
La desventaja de la inclusión en línea se convierte en un problema cuando significa que debe incorporar detalles de implementación en su encabezado, es decir, debe comenzar a incluir encabezados adicionales.
Tenga en cuenta que las plantillas son un caso especial, ya que prácticamente tiene que incluir los detalles de implementación. Puede ocultarlo en otro archivo pero debe estar allí. (Hay una excepción a esa regla con las instancias, pero en general usted alinea sus plantillas).
fuente
Puede que no sea significativo o verdadero si su ejecutable se hace más grande, pero más código en los archivos de encabezado le da al compilador más oportunidades de optimizar la velocidad.
Si decide si desea escribir una biblioteca de solo encabezado , este tema es solo una de sus preocupaciones.
fuente