2010-03-20 13 views

risposta

7

Se si desidera utilizzare un modello in un'altra unità di traduzione (ad esempio un altro file di origine), è necessario (quasi sempre) definirlo nel file di intestazione. (Esistono alcune eccezioni, come i commenti sottostanti, ma questa è una buona regola.)

Lo stesso si applica se si desidera utilizzare una funzione inline da un'altra unità di traduzione.

Altrimenti dovresti inserire l'implementazione in un file .cpp separato per ridurre al minimo le dipendenze.

+2

Come per i modelli, non è strettamente vero che è necessario inserire le definizioni di funzione (membro) nel file di intestazione. È possibile inserire le definizioni in un file sorgente e utilizzare l'istanziazione esplicita del modello per rendere disponibili particolari specializzazioni ... –

+0

@STingRaySC Sì, ho avuto alcuni ricordi vaghi dai modelli C++ che è possibile, anche se non l'ho mai fatto da solo. Tuttavia, ho cercato di dare una regola generale che è buona per i principianti e quasi sempre applicabile. Entrare nei casi speciali è per gli esperti (di cui non sono uno :-) –

+0

E non devi fornire implementazioni di modelli nel file di intestazione se il tuo compilatore supporta l'esportazione – smerlin

3

Capire questo problema è fondamentalmente capire come funzionano le unità di compilazione C++. Le cose nei file di intestazione sono fondamentalmente incollate nel codice sorgente di un gruppo di unità di compilazione per le dichiarazioni #include. Ogni unità di compilazione viene compilata in un file oggetto, i file oggetto vengono collegati e si verificano conflitti a causa del fatto che tali elementi vengono replicati dappertutto.

Le eccezioni sono cose che (storicamente, almeno) non entrano nel file oggetto perché il compilatore si occupa direttamente di esse (ad es. Funzioni inline) e cose che non possono essere compilate in una unità e collegate a un altro perché non sono completamente definiti (modelli). Le funzioni template spesso vengono istanziate in modo identico in più unità di compilazione e il linker ha speciali intelligenze per scartare i duplicati.

Ciò significa che la separazione dell'interfaccia e dell'implementazione nei file di intestazione e corpo non è molto pulita. Ada ha una separazione molto più pulita - ma un processo di compilazione più complesso per compensare IIRC. Java ha semplicemente rilasciato i file separati per l'interfaccia e l'implementazione.

I linker sono diventati molto più sofisticati nel corso degli anni e hanno assorbito parte del lavoro del compilatore, e molte di queste spiegazioni sono semplicemente sbagliate in questi giorni, eppure i modelli di base rimangono. Le funzioni template e le funzioni inline possono (e spesso devono) andare nell'intestazione, insieme a tutte le dichiarazioni condivise del codice don -t-direttamente-generate-oggetto-oggetto. Le definizioni di funzioni normali non dovrebbero essere in un file di intestazione.

+0

In realtà, i linker non sono così intelligenti riguardo alle istanze di 'template'. Prenderanno fondamentalmente il primo che incontrano e si affideranno a ** ODR ** (una regola di definizione). Può portare a un bug difficile da trovare se solo una parte delle estensioni 'Foo ' utilizza una specializzazione! –

Problemi correlati