Perché forward-declare è necessario in C ++
Il compilatore desidera assicurarsi di non aver commesso errori di ortografia o di aver passato il numero errato di argomenti alla funzione. Quindi, insiste sul fatto che vede prima una dichiarazione di 'add' (o qualsiasi altro tipo, classe o funzione) prima che venga usata.
Questo in realtà consente al compilatore di fare un lavoro migliore nella convalida del codice e gli consente di riordinare le estremità libere in modo da poter produrre un file oggetto dall'aspetto pulito. Se non fosse necessario inoltrare dichiarazioni, il compilatore produrrebbe un file oggetto che dovrebbe contenere informazioni su tutte le possibili ipotesi su quale potrebbe essere la funzione 'aggiungi'. E il linker dovrebbe contenere una logica molto intelligente per provare a capire quale 'aggiungere' in realtà intendevi chiamare, quando la funzione 'aggiungi' potrebbe vivere in un diverso file oggetto il linker si unisce a quello che usa aggiungi per produrre una dll o exe. È possibile che il linker ottenga l'aggiunta errata. Supponiamo che tu voglia utilizzare int add (int a, float b), ma hai accidentalmente dimenticato di scriverlo, ma il linker ha trovato un int add già esistente (int a, int b) e ho pensato che fosse quello giusto e invece l'ho usato. Il codice verrà compilato, ma non farebbe ciò che ti aspettavi.
Quindi, solo per mantenere le cose esplicite ed evitare le supposizioni, ecc., Il compilatore insiste sul fatto che dichiari tutto prima di essere utilizzato.
Differenza tra dichiarazione e definizione
Per inciso, è importante conoscere la differenza tra una dichiarazione e una definizione. Una dichiarazione fornisce solo abbastanza codice per mostrare come appare qualcosa, quindi per una funzione, questo è il tipo restituito, che chiama la convenzione, il nome del metodo, gli argomenti e i loro tipi. Ma il codice per il metodo non è richiesto. Per una definizione, è necessaria la dichiarazione e quindi anche il codice per la funzione.
In che modo le dichiarazioni a termine possono ridurre significativamente i tempi di costruzione
Puoi ottenere la dichiarazione di una funzione nel tuo file .cpp o .h corrente # includendo l'intestazione che contiene già una dichiarazione della funzione. Tuttavia, questo può rallentare la compilazione, soprattutto se # includi un'intestazione in un .h invece di .cpp del tuo programma, poiché tutto ciò che # include il .h che stai scrivendo finirebbe # includendo tutte le intestazioni hai scritto anche #includes. Improvvisamente, il compilatore ha #incluso pagine e pagine di codice che deve compilare anche quando si desidera utilizzare solo una o due funzioni. Per evitare ciò, è possibile utilizzare una dichiarazione in avanti e digitare la dichiarazione della funzione da soli nella parte superiore del file. Se stai usando solo alcune funzioni, questo può davvero rendere le tue compilazioni più veloci rispetto al sempre #incluso l'intestazione. Per progetti davvero grandi,
Rompere i riferimenti ciclici in cui due definizioni si usano entrambe
Inoltre, le dichiarazioni anticipate possono aiutarti a interrompere i cicli. Qui è dove due funzioni cercano entrambe di usarsi. Quando ciò accade (ed è una cosa perfettamente valida da fare), puoi #includere un file di intestazione, ma quel file di intestazione cerca di #includere il file di intestazione che stai scrivendo .... che quindi # include l'altra intestazione , che # include quello che stai scrivendo. Sei bloccato in una situazione di pollo e uova con ogni file di intestazione che cerca di reincludere l'altro. Per risolvere questo problema, puoi inoltrare in anticipo le parti necessarie in uno dei file e lasciare #include da quel file.
Per esempio:
File Car.h
#include "Wheel.h" // Include Wheel's definition so it can be used in Car.
#include <vector>
class Car
{
std::vector<Wheel> wheels;
};
File Wheel.h
Hmm ... qui è richiesta la dichiarazione di Car in quanto Wheel ha un puntatore a una Car, ma Car.h non può essere incluso qui in quanto comporterebbe un errore del compilatore. Se Car.h fosse incluso, ciò proverebbe quindi a includere Wheel.h che includerebbe Car.h che includerebbe Wheel.h e questo continuerebbe per sempre, quindi il compilatore genera un errore. La soluzione è invece di dichiarare Car invece:
class Car; // forward declaration
class Wheel
{
Car* car;
};
Se la classe Wheel avesse metodi che devono chiamare metodi di auto, tali metodi potrebbero essere definiti in Wheel.cpp e Wheel.cpp è ora in grado di includere Car.h senza causare un ciclo.