Innanzitutto, per rispondere alla tua prima richiesta:
Quando vedi questo nel file .h :
#ifndef FILE_H
#define FILE_H
/* ... Declarations etc here ... */
#endif
Questa è una tecnica di preprocessore per impedire che un file di intestazione venga incluso più volte, il che può essere problematico per vari motivi. Durante la compilazione del progetto, ogni file .cpp (di solito) viene compilato. In termini semplici, questo significa che il compilatore prenderà il tuo file .cpp , aprirà tutti i file #includedda esso, li concatenerà tutti in un unico file di testo, quindi eseguirà l'analisi della sintassi e infine lo convertirà in un codice intermedio, ottimizzerà / eseguirà altri attività e infine generare l'output dell'assembly per l'architettura di destinazione. Per questo motivo, se un file è #includedpiù volte sotto un .cppfile, il compilatore aggiungerà il contenuto del suo file due volte, quindi se ci sono definizioni all'interno di quel file, otterrai un errore del compilatore che ti dice che hai ridefinito una variabile. Quando il file viene elaborato dal passaggio del preprocessore nel processo di compilazione, la prima volta che viene raggiunto il suo contenuto, le prime due righe controlleranno se FILE_Hè stato definito per il preprocessore. In caso contrario, definirà FILE_He continuerà a elaborare il codice tra esso e la #endifdirettiva. Alla successiva visualizzazione del contenuto del file da parte del preprocessore, il segno di spunta FILE_Hsarà falso, quindi scansionerà immediatamente verso il basso #endife continuerà dopo di esso. Questo impedisce errori di ridefinizione.
E per rispondere alla tua seconda preoccupazione:
Nella programmazione C ++ come pratica generale separiamo lo sviluppo in due tipi di file. Uno è con un'estensione di .h e lo chiamiamo un "file di intestazione". Di solito forniscono una dichiarazione di funzioni, classi, strutture, variabili globali, errori di battitura, macro e definizioni di preelaborazione, ecc. Fondamentalmente, forniscono semplicemente informazioni sul codice. Quindi abbiamo l' estensione .cpp che chiamiamo "file di codice". Ciò fornirà definizioni per quelle funzioni, membri della classe, tutti i membri della struttura che hanno bisogno di definizioni, variabili globali, ecc. Quindi il file .h dichiara il codice e il file .cpp implementa tale dichiarazione. Per questo motivo, generalmente durante la compilazione compiliamo ogni .cppfile in un oggetto e quindi collegare tali oggetti (poiché non si vede quasi mai un file .cpp che include un altro file .cpp ).
Come vengono risolti questi esterni è un lavoro per il linker. Quando il compilatore elabora main.cpp , ottiene le dichiarazioni per il codice in class.cpp includendo class.h . Deve solo sapere come appaiono queste funzioni o variabili (che è ciò che ti dà una dichiarazione). Quindi compila il tuo file main.cpp in qualche file oggetto (chiamalo main.obj ). Allo stesso modo, class.cpp è compilato in un class.objfile. Per produrre l'eseguibile finale, viene richiamato un linker per collegare insieme questi due file oggetto. Per eventuali variabili o funzioni esterne non risolte, il compilatore inserirà uno stub in cui avviene l'accesso. Il linker prenderà quindi questo stub e cercherà il codice o la variabile in un altro file oggetto elencato e, se viene trovato, combina il codice dei due file oggetto in un file di output e sostituisce lo stub con la posizione finale della funzione o variabile. In questo modo, il tuo codice in main.cpp può chiamare funzioni e usare variabili in class.cpp SE E SOLO SE SONO DICHIARATE IN class.h .
Spero sia stato utile.