Éviter les dépendances circulaires des fichiers d'en-tête [dupliquer]
cette question a déjà une réponse ici:
avez-vous un bon conseil sur la façon d'éviter les dépendances circulaires des fichiers d'en-tête , s'il vous plaît?
Bien sûr, depuis le début, j'essaie de concevoir le projet aussi transparent que possible. Cependant, à mesure que de plus en plus de fonctionnalités et de classes sont ajoutées et que le projet devient moins transparent, des dépendances circulaires commencent à se produire.
y a-t-il des règles générales, vérifiées et opérationnelles? Merci.
8 réponses
si vous avez une dépendance circulaire, alors vous faites quelque chose de mal.
comme par exemple:
foo.h
-----
class foo {
public:
bar b;
};
bar.h
-----
class bar {
public:
foo f;
};
Est illégale, vous voulez probablement:
foo.h
-----
class bar; // forward declaration
class foo {
...
bar *b;
...
};
bar.h
-----
class foo; // forward declaration
class bar {
...
foo *f;
...
};
et c'est ok.
règles générales:
- assurez-vous que chaque en-tête peut être inclus sur son propre.
- si vous pouvez utiliser des déclarations forward, utilisez-les!
- utiliser les déclarations transmises lorsque cela est possible.
- déplacer n'importe quel en-tête inclut hors d'un dossier d'en-tête et dans le dossier de cpp correspondant si elles sont seulement nécessaires par le dossier de cpp. La façon la plus facile de faire respecter ceci est de faire le
#include "myclass.h"
la première inclusion dansmyclass.cpp
. - L'Introduction d'interfaces au point d'interaction entre classes séparées peut aider à réduire les dépendances.
Une approche générale consiste à factoriser les points communs dans un troisième fichier d'en-tête qui est référencée par l'original deux fichiers d'en-tête.
Voir aussi meilleures pratiques en matière de dépendance circulaire
"certaines des meilleures pratiques que j'utilise pour éviter les dépendances circulaires sont,
- Stick to OAD principles. Ne pas inclure un fichier d'en-tête, à moins que la classe incluse soit en relation avec la classe courante. Utilisez plutôt la déclaration forward.
- classes d'abrégé de dessin servant d'interface pour deux classes. Faites l'interaction des classes à travers cette interface.
selon vos capacités de préprocesseur:
#pragma once
ou
#ifndef MY_HEADER_H
#define MY_HEADER_H
your header file
#endif
si vous trouvez qu'il est très ennuyeux de concevoir des fichiers en-tête peut-être makeheaders de Hwaci (concepteurs de DVCS SQLite et fossiles) pourrait être d'intérêt pour vous.
ce que vous visez est une approche à plusieurs niveaux . Vous pouvez définir des couches où les modules peuvent dépendre de modules de couches inférieures, mais l'inverse doit être fait avec observateurs . Maintenant, vous pouvez encore définir à quel point vos couches doivent être fines et si vous acceptez la dépendance circulaire à l'intérieur des couches, mais dans ce cas j'utiliserais ceci .
en général, les fichiers d'en-tête doivent déclarer forwardly plutôt que d'inclure d'autres en-têtes dans la mesure du possible.
assure également que vous vous en tenez à une classe par en-tête.
alors vous ne vous tromperez presque certainement pas.
le pire couplage provient généralement du code template gonflé. Parce que vous devez inclure la définition à l'intérieur de l'en-tête, il conduit souvent à toutes sortes headers devant être inclus, et puis la classe que utilise le modèle inclut l'en-tête de modèle, y compris une charge d'autres choses.
pour cette raison, je dirais généralement: soyez prudent avec les gabarits! Idéalement, un modèle ne devrait pas avoir à inclure quoi que ce soit dans son code de mise en œuvre.
Altough Artyom meilleure réponse fournie ce tutoriel est également grand et fournit quelques extenstions http://www.cplusplus.com/forum/articles/10627/