c++ - Evitar las dependencias circulares de los archivos de encabezado
software-design architecture (8)
Esta pregunta ya tiene una respuesta aquí:
¿Tiene algún buen consejo sobre cómo evitar las dependencias circulares de los archivos de encabezado , por favor?
Por supuesto, desde el principio, intento 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.
Algunas de las mejores prácticas que sigo para evitar las dependencias circulares son,
- 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 declaración directa en su lugar.
- 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.
Aunque Artyom brindó la mejor respuesta, este tutorial también es excelente y proporciona algunas extensiones http://www.cplusplus.com/forum/articles/10627/
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.
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 observers . 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 this .
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:
- Asegúrese de que cada encabezado se pueda incluir por sí mismo.
- Si puede usar declaraciones hacia adelante, ¡utilícelas!
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
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 makeheaders de Hwaci (diseñadores de SQLite y fósil DVCS) le puedan interesar.
- 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 enmyclass.cpp
. - La introducción de interfaces en el punto de interacción entre clases separadas puede ayudar a reducir las dependencias.