Naja, das ist jetzt ein bisschen Begriffsverwischung

Mit "in der Klasse" meinst du wohl "in der .cpp-Datei", oder?
ghorst hat es schon gesagt, der Präprozessor macht für jede .cpp eine entsprechende Datei, wo er alle includes "reinkleistert", alle Makros expandiert etc.
Machen wir mal ein simples Beispiel:
a.h:
... irgendwas
b.h:
#include "a.h"
main.cpp
#include "a.h"
#include "b.h"
Dann wird jetzt beim Kompilieren von main.cpp zuerst #include "a.h" expandiert und der Header dort reinkopiert. Jetzt wird b.h expandiert, welches selbst erstmal wieder a.h expandieren will. Da wir in a.h zum Glück include-Guards verwendet haben, expandiert sich a.h in b.h nicht mehr (sonst gäb's mehrfache Definitionen, was eine Verletzung der ODR (One Definition Rule) wäre). Damit steht dann in der generierten main.cpp zuerst der Inhalt von a.h, dann b.h, dann main.cpp. (Man sieht übrigens: main.cpp hängt von a.h und b.h ab, muss also bei einer Änderung in a.h oder b.h neu kompiliert werden)
Soviel dazu.
Die Frage ob forward oder include: Include nur dann, wenn es wirklich unbedingt benötigt wird - sonst forward.
Beispiel für einen schlechten Header:
a.h
Code:
#ifndef A_H
#define A_H
#include "b.h" // für Klasse B
#include "c.h" // für Klasse C
#include "d.h" // für Klasse D
#include "e.h" // für Klasse E
#include <iostream>
class A : public E
{
public:
A( B*);
void doSomething( const D&);
private:
C c_;
};
std::ostream& operator<<( std::ostream&, const A&);
#endif
Was ist an diesem Header schlecht? Wer ihn inkludiert, hängt von e.h, b.h, c.h und d.h ab und muss zusätzlich das include-Monster iostream einbinden, auch wenn man sich überhaupt nicht für den operator<< interessiert (sprich ihn nicht verwendet). Includiert man a.h, wird man auch bei einer Änderung von b.h, c.h, d.h und e.h neu kompiliert.
Nur das #include "e.h" und #include "c.h" wird hier wirklich benötigt. Wobei sich das #include "c.h" sogar vermeiden ließe.
Warum ist das so? Fangen wir mit dem Einfachen an: Wir leiten von E ab, also muss die Definition von E vollständig bekannt sein.
Der Konstruktor von A bekommt einen Pointer auf B. Zur Übergabe des Zeigers muss die Definition von B aber nicht bekannt sein. Es wird im Header nur der Zeiger verwendet, nicht B selbst. Damit reicht es, b.h durch eine Forwarddeklaration class B; zu ersetzen. Schwups, ein Header von dem wir nicht mehr abhängen.
Das selbe trifft auf die Methode doSomething zu, die eine const-Referenz auf D bekommt. D selbst wird bei der Übergabe nicht verwendet. #include "d.h" ist überflüssig - raus damit, Forward-Deklaration rein.
Nun zur Membervariable c_ vom Typ C. C ist ein Bestandteil von A. Ohne Vollständige Kenntnis von C können wir kein A definieren. Include muss sein. .... Wirklich? Wenn ich A benutzen will, interessiert mich doch nur seine öffentliche Schnittstelle und nicht irgendwelche Interna. Obwohl mich C nicht die Bohne interessiert und ich es nicht verwende, hänge ich von ihm ab. -> DOOF. In Anbetracht des obigen: Ändert man C c_; in C* c_; , so muss man nur einen Zeiger auf ein C halten - womit C im Header nicht mehr bekannt sein muss. Puh *Schweiß wegwisch*, wieder eine Abhängigkeit entfernt.
(Man sollte aber nicht den Nachteil dieser Technik verschweigen: Ab sofort muss man einen vernünftigen Zuweisungsoperator und Kopierkonstruktor zur Verfügung stellen, da der Compilergenerierte es nicht mehr sinnvoll tut. Außerdem muss man sich um das Löschen von C kümmern. Und der Zeitbedarf für die Allokierung mit new ist wie das Fahren mit angezogener Handbremse im Vergleich zum Stack)
Nun noch zum operator<< : Wenn ich A benutzen will, will ich es aber noch lange nicht auch ausgeben. Ich interessiere mich nicht für ihn und will auch nicht dieses superfette #include <iostream> da (iostream ist der größte Header der Standardbibliothek, bzw. zieht am meisten Abhängigkeiten mit sich). Vor dem C++ Standard konnten wir noch sowas schönes schreiben wie: class ostream; und wir waren aus dem Schneider. Mit dem Standard ist ostream aber in den Namensraum std gewandert. Okay, machen wir das hier:
Code:
namespace std { class ostream; }
Sieht gut aus, ist es aber nicht. ostream ist nämlich nur ein Typedef auf basic_ostream<char, char_traits<char> >. Dies wiederum dürfen wir aber nicht forward deklarieren (aus Gründen, die für alle STL-Klassen zutreffen). Zum Glück hat der Standard die armen Benutzer von <iostream> bedacht und den Header <iosfwd> spendiert, der Forward-Deklarationen auf alle Streamklassen definiert. Prima! <iostream> raus, <iosfwd> rein. (Übrigens: Auf andere STL-Klassen wie string und vector lassen sich
keine standardkonformen Forwarddeklarationen hinschreiben)
Nun haben wir alle Abhängigkeiten aus dem Header eliminiert, die sich eliminieren lassen! Und das durch forward-Deklarationen. Deshalb sind Forward-Deklarationen Includes vorzuziehen.
Man sollte sich durch eine Sache nicht täuschen lassen. Wenn man z.B. jetzt den Operator << auch
verwenden will, kommt man um das #include <iostream> nicht herum (dann natürlich das include nur in der .cpp Datei, wo er aufgerufen wird). Braucht man ihn aber garnicht, ist <iostream> unnötiger Ballast und <iosfwd> angebracht.