Evitar las dependencias circulares de los archivos de encabezado

¿Tiene algún buen consejo sobre cómo evitar las dependencias circulares de los archivos de encabezado , por favor?

Por supuesto, desde el principio, bash diseñar el proyecto lo más transparente posible. Sin embargo, a medida que se agregan más y más características y clases, y el proyecto se vuelve menos transparente, comienzan a ocurrir dependencias circulares.

¿Hay reglas generales, verificadas y de trabajo? Gracias.

Si tiene dependencia circular, entonces está haciendo algo mal.

Como por ejemplo:

foo.h ----- class foo { public: bar b; }; bar.h ----- class bar { public: foo f; }; 

Es ilegal, probablemente quieras:

 foo.h ----- class bar; // forward declaration class foo { ... bar *b; ... }; bar.h ----- class foo; // forward declaration class bar { ... foo *f; ... }; 

Y esto está bien.

Reglas generales:

  1. Asegúrese de que cada encabezado se pueda incluir por sí mismo.
  2. Si puede usar declaraciones hacia adelante, ¡utilícelas!
  • Use declaraciones adelante siempre que sea posible.
  • Mueva cualquier encabezado incluido fuera de un archivo de encabezado y en el archivo cpp correspondiente si solo lo necesita el archivo cpp. La forma más sencilla de hacer cumplir esto es hacer que el #include "myclass.h" el primero incluido en myclass.cpp .
  • La introducción de interfaces en el punto de interacción entre clases separadas puede ayudar a reducir las dependencias.

Un enfoque general es factorizar las características comunes en un tercer archivo de encabezado al que los dos archivos de encabezado originales hacen referencia.

Ver también Buenas Prácticas de Dependencia Circular

Algunas de las mejores prácticas que sigo para evitar las dependencias circulares son,

  1. Aténgase a los principios de OOAD. No incluya un archivo de encabezado, a menos que la clase incluida esté en relación de composición con la clase actual. Use la statement directa en su lugar.
  2. Diseña clases abstractas para que actúen como interfaces para dos clases. Haga la interacción de las clases a través de esa interfaz.

según las capacidades de tu preprocesador:

 #pragma once 

o

 #ifndef MY_HEADER_H #define MY_HEADER_H your header file #endif 

Si le resulta muy aburrido diseñar archivos de cabecera, quizás las cabeceras de Hwaci (diseñadores de SQLite y fósil DVCS) le puedan interesar.

Lo que pretendes es un enfoque en capas . Puede definir capas donde los módulos pueden depender de módulos de capa inferior, pero la inversa debe hacerse con observadores . Ahora todavía puede definir qué tan finas deben ser sus capas y si acepta la dependencia circular dentro de las capas, pero en este caso usaría esto .

En general, los archivos de encabezado deben declarar en lugar de incluir otros encabezados cuando sea posible.

También asegúrate de mantenerte en una clase por encabezado.

Entonces, casi seguro que no te equivocarás.

El peor acoplamiento generalmente proviene del código de la plantilla hinchada. Como tiene que incluir la definición dentro del encabezado, a menudo conduce a que se tengan que incluir todos los encabezados de clases, y luego la clase que usa la plantilla incluye el encabezado de la plantilla, que incluye una carga de otras cosas.

Por esta razón, generalmente diría: ¡ten cuidado con las plantillas! Idealmente, una plantilla no debería tener que incluir nada en su código de implementación.

Aunque Artyom brindó la mejor respuesta, este tutorial también es excelente y proporciona algunas extensiones http://www.cplusplus.com/forum/articles/10627/