it-swarm.com.de

Vermeiden von zirkulären Abhängigkeiten von Header-Dateien

Haben Sie einen guten Rat, wie Sie zirkuläre Abhängigkeiten von Header-Dateien vermeiden können?

Natürlich versuche ich von Anfang an, das Projekt so transparent wie möglich zu gestalten. Da jedoch immer mehr Features und Klassen hinzugefügt werden und das Projekt weniger transparent wird, treten kreisförmige Abhängigkeiten auf.

Gibt es allgemeine, überprüfte und funktionierende Regeln? Danke.

50
Bunkai.Satori

Wenn Sie Kreislaufabhängigkeit haben, dann tun Sie etwas falsch.

Wie zum Beispiel:

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

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

Ist illegal, was Sie wahrscheinlich wollen:

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

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

Und das ist in Ordnung.

Allgemeine Regeln:

  1. Stellen Sie sicher, dass jeder Header für sich aufgenommen werden kann.
  2. Wenn Sie Forward-Deklarationen verwenden können, verwenden Sie diese!
49
Artyom
  • Verwenden Sie nach Möglichkeit Vorwärtserklärungen.
  • Verschieben Sie alle Header-Includes aus einer Header-Datei in die entsprechende CPP-Datei, wenn sie nur von der CPP-Datei benötigt werden. Der einfachste Weg, dies durchzusetzen, besteht darin, das #include "myclass.h" das erste include in myclass.cpp.
  • Durch die Einführung von Schnittstellen an der Stelle der Interaktion zwischen verschiedenen Klassen können Abhängigkeiten verringert werden.
15
jon-hanson

Einige Best Practices, die ich befolge, um zirkuläre Abhängigkeiten zu vermeiden, sind:

  1. Halten Sie sich an die OOAD-Prinzipien. Fügen Sie keine Header-Datei hinzu, es sei denn, die enthaltene Klasse steht in einer Kompositionsbeziehung mit der aktuellen Klasse. Verwenden Sie stattdessen die Forward-Deklaration.
  2. Entwerfen Sie abstrakte Klassen als Schnittstellen für zwei Klassen. Stellen Sie die Interaktion der Klassen über diese Schnittstelle her.
7
Sulla

Ein allgemeiner Ansatz besteht darin, die Gemeinsamkeiten in eine dritte Header-Datei zu zerlegen, auf die dann von den beiden ursprünglichen Header-Dateien verwiesen wird.

Siehe auch Circular Dependency Best Practice

6
Ed Guiness

abhängig von Ihren Präprozessor-Fähigkeiten:

#pragma once

oder

#ifndef MY_HEADER_H
#define MY_HEADER_H
your header file
#endif

Wenn Sie es sehr langweilig finden, Header-Dateien zu entwerfen, könnte makeheaders von Hwaci (Designer von SQLite und Fossil DVCS) für Sie von Interesse sein.

4
Benoit

Im Allgemeinen sollten Header-Dateien nach Möglichkeit vorwärts deklarieren, anstatt andere Header einzuschließen.

Stellen Sie außerdem sicher, dass Sie sich an eine Klasse pro Header halten.

Dann werden Sie mit ziemlicher Sicherheit nichts falsch machen.

Die schlechteste Kopplung entsteht normalerweise durch aufgeblähten Vorlagencode. Da Sie die Definition in den Header einfügen müssen, müssen häufig alle Arten von Headern eingefügt werden, und dann enthält die Klasse, die die Vorlage verwendet, den Vorlagenheader, einschließlich einer Menge anderer Elemente.

Aus diesem Grund würde ich generell sagen: Vorsicht mit Vorlagen! Im Idealfall sollte eine Vorlage nichts in den Implementierungscode aufnehmen müssen.

3
CashCow

Was Sie anstreben, ist ein überlagerter Ansatz. Sie können Ebenen definieren, in denen Module von Modulen niedrigerer Ebenen abhängen können. Die Umkehrung sollte jedoch mit Beobachter erfolgen. Jetzt können Sie noch definieren, wie feinkörnig Ihre Ebenen sein sollen und ob Sie kreisförmige Abhängigkeiten innerhalb von Ebenen akzeptieren. In diesem Fall würde ich jedoch this verwenden.

3
stefaanv

Obwohl Artyom die beste Antwort geliefert hat, ist dieses Tutorial auch großartig und bietet einige Erweiterungen http://www.cplusplus.com/forum/articles/10627/

2
rank1