Tempo di pensare - Perché vuoi dividere il tuo file comunque?
Come suggerisce il titolo, il problema finale che ho sono errori di linker a più definizioni. Ho effettivamente risolto il problema, ma non ho risolto il problema nel modo corretto. Prima di iniziare voglio discutere i motivi per dividere un file di classe in più file. Ho provato a mettere qui tutti gli scenari possibili - se ne ho perso uno, per favore ricordamelo e posso apportare modifiche. Speriamo che i seguenti sono corretto:Separazione del codice di classe C++ in più file, quali sono le regole?
Motivo 1per risparmiare spazio:
Si dispone di un file contenente la dichiarazione di una classe con tutti i membri della classe. Puoi inserire #include protezioni attorno a questo file (o #pragma una volta) per garantire che non si verifichino conflitti se si include il file in due file di intestazione diversi che vengono quindi inclusi in un file sorgente. Compilate un file sorgente separato con l'implementazione di tutti i metodi dichiarati in questa classe, poiché carica molte righe di codice dal vostro file sorgente, il che pulisce un po 'le cose e introduce qualche ordine nel vostro programma.
Esempio: Come si può vedere, l'esempio di seguito potrebbe essere migliorato dividendo l'implementazione dei metodi di classe in un file diverso. (Un file cpp)
// my_class.hpp
#pragma once
class my_class
{
public:
void my_function()
{
// LOTS OF CODE
// CONFUSING TO DEBUG
// LOTS OF CODE
// DISORGANIZED AND DISTRACTING
// LOTS OF CODE
// LOOKS HORRIBLE
// LOTS OF CODE
// VERY MESSY
// LOTS OF CODE
}
// MANY OTHER METHODS
// MEANS VERY LARGE FILE WITH LOTS OF LINES OF CODE
}
Motivo 2Per evitare errori multipli definizione linker:
Forse questo è il motivo principale per cui si dovrebbe dividere implementazione da dichiarazione. Nell'esempio precedente, è possibile spostare il corpo del metodo all'esterno della classe. Questo lo renderebbe molto più pulito e strutturato. Tuttavia, in base a questo question, l'esempio precedente ha impliciti parametri inline
. Spostare l'implementazione dall'interno della classe all'esterno della classe, come nell'esempio seguente, causerà errori del linker, pertanto è necessario incorporare tutto o spostare le definizioni di funzione in un file .cpp.
Esempio: _L'esempio seguente causerà "errori di linker a più definizioni" se non si sposta la definizione di funzione in un file .cpp o si specifica la funzione come inline.
// my_class.hpp
void my_class::my_function()
{
// ERROR! MULTIPLE DEFINITION OF my_class::my_function
// This error only occurs if you #include the file containing this code
// in two or more separate source (compiled, .cpp) files.
}
per risolvere il problema:
//my_class.cpp
void my_class::my_function()
{
// Now in a .cpp file, so no multiple definition error
}
Oppure:
// my_class.hpp
inline void my_class::my_function()
{
// Specified function as inline, so okay - note: back in header file!
// The very first example has an implicit `inline` specifier
}
Motivo 3Si vuole risparmiare spazio, ancora una volta, ma questa volta si sta lavorando con una classe template:
Se stiamo lavorando con classi template, non possiamo spostare l'implementazione in un file sorgente (file .cpp). Questo non è attualmente consentito da (presumo) o dai compilatori standard o attuali. A differenza del primo esempio di Motivo 2, sopra, siamo autorizzati a posizionare l'implementazione nel file di intestazione.In base a questo question, la ragione è che i metodi di classe template hanno anche implicito gli specificatori inline
. È corretto? (Sembra avere un senso.) Ma nessuno sembrava sapere sulla domanda a cui ho appena fatto riferimento!
Quindi, i due esempi di seguito sono identici?
// some_header_file.hpp
#pragma once
// template class declaration goes here
class some_class
{
// Some code
};
// Example 1: NO INLINE SPECIFIER
template<typename T>
void some_class::class_method()
{
// Some code
}
// Example 2: INLINE specifier used
template<typename T>
inline void some_class::class_method()
{
// Some code
}
Se si dispone di un file di intestazione di classe template, che sta diventando enorme a causa di tutte le funzioni che avete, allora credo che si è permesso di spostare le definizioni di funzione a un altro file di intestazione (di solito un file .tpp?) e quindi #include file.tpp
alla fine del file di intestazione contenente la dichiarazione della classe. NON devi includere questo file da nessun'altra parte, tuttavia, di conseguenza lo .tpp
anziché lo .hpp
.
Suppongo che si possa fare anche con i metodi in linea di una classe regolare? È permesso anche questo?
il tempo delle interrogazioni
così ho fatto alcune dichiarazioni di cui sopra, la maggior parte dei quali riguardano la strutturazione del file di origine. Penso che tutto ciò che ho detto sia corretto, perché ho fatto alcune ricerche di base e "ho scoperto alcune cose", ma questa è una domanda e quindi non lo so per certo.
Ciò a cui si riferisce è come organizzare il codice all'interno dei file. Penso di aver capito una struttura che funzionerà sempre.
Ecco quello che ho trovato. (Questo è "organizzazione file di codice di classe/struttura standard di Ed Uccello", se ti piace non so se sarà molto utile ancora, questo è il punto di chiedere..)
- 1: Dichiarare la classe (modello o altro) in un file
.hpp
, inclusi tutti i metodi, le funzioni di amicizia e i dati. - 2: Nella parte inferiore del file
.hpp
,#include
un file.tpp
contenente l'attuazione di eventualiinline
metodi. Creare il file.tpp
e assicurarsi che tutti i metodi siano specificati ininline
. - 3: Tutti gli altri membri (funzioni non-inline, funzioni amico e dati statici) dovrebbero essere definiti in un file
.cpp
, che#include
s il file.hpp
in alto per evitare errori come "classe ABC non è stato dichiarato ". Poiché tutto in questo file avrà un collegamento esterno, il programma si collegherà correttamente.
standard come questo esistono nell'industria? Lo standard mi ha insegnato a lavorare in tutti i casi?
btw Ho scremato la tua domanda perché era troppo lunga. Informazioni sulla funzione del modello in linea. La parola chiave inline non è richiesta (hai ancora il permesso di inserirli nei file header) e non ha alcun effetto garantito. L'uso della parola chiave potrebbe rendere il compilatore più probabile che inline la funzione, ma nulla è certo. Queste funzioni del modello non sono implicitamente funzioni inline. La risposta a questa domanda è sbagliata, come discusso nei commenti della risposta. –
@NeilKirk Ah grazie, la certezza sembrava esserci molto disaccordo a riguardo. – user3728501
Ignora semplicemente mettere in linea lì e il problema non ti disturberà mai :) –