Sollte man nach Möglichkeit Forward-Deklarationen anstelle von Includes verwenden?
Nein, explizite Vorwärtserklärungen sollten nicht als allgemeine Richtlinie betrachtet werden. Vorwärtsdeklarationen sind im Wesentlichen kopierte und eingefügte oder falsch geschriebene Codes, die, falls Sie einen Fehler darin finden, überall dort behoben werden müssen, wo die Vorwärtsdeklarationen verwendet werden. Dies kann fehleranfällig sein.
Um Nichtübereinstimmungen zwischen den "Vorwärts" -Deklarationen und ihren Definitionen zu vermeiden, fügen Sie Deklarationen in eine Header-Datei ein und fügen Sie diese Header-Datei sowohl in die definierenden als auch in die deklarationsverwendenden Quelldateien ein.
In diesem speziellen Fall, in dem nur eine undurchsichtige Klasse vorwärts deklariert ist, ist diese Vorwärtsdeklaration möglicherweise in Ordnung, aber im Allgemeinen kann "Vorwärtsdeklarationen anstelle von Includes verwenden, wann immer dies möglich ist", wie der Titel dieses Threads besagt sei ziemlich riskant.
Hier einige Beispiele für "unsichtbare Risiken" in Bezug auf Vorwärtsdeklarationen (unsichtbare Risiken = Deklarationsfehlanpassungen, die vom Compiler oder Linker nicht erkannt werden):
Explizite Vorwärtsdeklarationen von Symbolen, die Daten darstellen, können unsicher sein, da solche Vorwärtsdeklarationen möglicherweise die korrekte Kenntnis des Footprints (der Größe) des Datentyps erfordern.
Explizite Vorwärtsdeklarationen von Symbolen, die Funktionen darstellen, können ebenso unsicher sein wie die Parametertypen und die Anzahl der Parameter.
Das folgende Beispiel veranschaulicht dies, z. B. zwei gefährliche Vorwärtsdeklarationen von Daten sowie einer Funktion:
Datei ac:
#include <iostream>
char data[128][1024];
extern "C" void function(short truncated, const char* forgotten) {
std::cout << "truncated=" << std::hex << truncated
<< ", forgotten=\"" << forgotten << "\"\n";
}
Datei bc:
#include <iostream>
extern char data[1280][1024];
extern "C" void function(int tooLarge);
int main() {
function(0x1234abcd);
std::cout << "accessing data[1270][1023]\n";
return (int) data[1270][1023];
}
Kompilieren des Programms mit g ++ 4.7.1:
> g++ -Wall -pedantic -ansi a.c b.c
Hinweis: Unsichtbare Gefahr, da g ++ keine Compiler- oder
Linkerfehler / Warnungen ausgibt. Hinweis: Das Weglassen extern "C"
führt zu einem Verknüpfungsfehler function()
aufgrund des Mangels des C ++ - Namens.
Ausführen des Programms:
> ./a.out
truncated=abcd, forgotten="♀♥♂☺☻"
accessing data[1270][1023]
Segmentation fault