Formas de organizar la interfaz y la implementación en C ++

12

He visto que hay varios paradigmas diferentes en C ++ relacionados con lo que se incluye en el archivo de encabezado y con el archivo cpp. AFAIK, la mayoría de las personas, especialmente las de fondo 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 generalmente enseñan 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

Originalmente proveniente de Java, también siempre me he limitado a esta segunda forma por varias razones, como que solo tengo que cambiar algo en un lugar si la interfaz o los nombres de los métodos cambian, me gusta la sangría diferente de las cosas en clases cuando veo su implementación, y me parece que los nombres son más legibles como foo en comparación con foo::foo .

Quiero recopilar los pros y los contras de cualquier manera. Tal vez incluso hay otras formas?

Una desventaja de mi camino es, por supuesto, la necesidad de declaraciones prospectivas ocasionales.

    
pregunta Felix Dombek 17.02.2011 - 11:25

4 respuestas

15

Aunque 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 exponga los detalles de la implementación , obtendrá recompilación innecesaria con la segunda versión.

    
respondido por el LennyProgrammers 17.02.2011 - 12:11
3

Lo hice la segunda vuelta en el '93 -95. Tardé unos minutos en volver a compilar una aplicación pequeña con 5-10 funciones / archivos (en esa misma 486 PC ... y no, tampoco sabía acerca de las clases, tenía solo 14-15 años y había no internet ).

Entonces, lo que enseñan a los principiantes y lo que usan profesionalmente son técnicas muy diferentes, especialmente en C ++.

Creo que la comparación entre C ++ y un coche de F1 es adecuada. No pones a los principiantes en un coche de F1 (que ni siquiera arranca a menos que precalientes el motor a 80-95 grados centígrados).

No enseñes C ++ como primera lengua. 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.

    
respondido por el Macke 17.02.2011 - 12:22
2

El segundo método es lo que yo llamaría una clase totalmente en línea. Estás escribiendo una definición de clase, pero todo el código que usas solo lo alineará.

Sí, el compilador decide cuándo en línea y cuándo no ... En este caso, sin embargo, 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, debe reconstruir todo el origen que la utiliza. En la naturaleza liviana de la clase no modificará la implementación. Si agrega un nuevo método, tendría que modificar el encabezado de todos modos.

A medida que su clase se vuelve más compleja, sin embargo, incluso al agregar un bucle, la ventaja de hacerlo de esta manera disminuye.

Todavía tiene sus ventajas, en particular:

  • Si este es un código de "funcionalidad común", puede incluir el encabezado y usarlo desde múltiples proyectos sin tener que vincularse con una biblioteca que contiene su fuente.

La desventaja de la inclusión en línea se convierte en un problema cuando significa que debe incluir los detalles de la 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 debe incluir los detalles de la 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).

    
respondido por el CashCow 17.02.2011 - 14:10
1

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 permite al compilador más posibilidades de optimizar la velocidad.

Si decide si desea escribir una biblioteca de solo encabezado , este tema es solo una de sus preocupaciones.

    
respondido por el davidvandebunte 27.10.2017 - 02:05

Lea otras preguntas en las etiquetas