* .h o * .hpp per le definizioni della classe


555

Ho sempre usato un *.hfile per le definizioni della mia classe, ma dopo aver letto un po 'di codice della libreria boost, mi sono reso conto che tutti usano *.hpp. Ho sempre avuto un'avversione per l'estensione del file, penso principalmente perché non ci sono abituato.

Quali sono i vantaggi e gli svantaggi dell'utilizzo di *.hppover *.h?

Risposte:


528

Ecco un paio di ragioni per avere nomi diversi delle intestazioni C vs C ++:

  • Formattazione automatica del codice, potresti avere diverse linee guida per la formattazione del codice C e C ++. Se le intestazioni sono separate per estensione, puoi impostare il tuo editor per applicare automaticamente la formattazione appropriata
  • Denominando, ho partecipato a progetti in cui c'erano librerie scritte in C e quindi i wrapper erano stati implementati in C ++. Dato che le intestazioni di solito avevano nomi simili, cioè Feature.h vs Feature.hpp, erano facili da distinguere.
  • Inclusione, forse il tuo progetto ha versioni più appropriate disponibili scritte in C ++ ma stai usando la versione C (vedi punto sopra). Se le intestazioni prendono il nome dalla lingua in cui sono implementate, puoi facilmente individuare tutte le intestazioni C e verificare la presenza di versioni C ++.

Ricorda, C non è C ++ e può essere molto pericoloso mescolare e abbinare se non sai cosa stai facendo. Dare un nome appropriato alle tue fonti ti aiuta a distinguere le lingue.


234

Uso .hpp perché voglio che l'utente distingua quali intestazioni sono intestazioni C ++ e quali intestazioni sono intestazioni C.

Questo può essere importante quando il tuo progetto utilizza entrambi i moduli C e C ++: Come qualcun altro ha spiegato prima di me, dovresti farlo con molta attenzione, e inizia con il "contratto" che offri attraverso l'estensione

.hpp: intestazioni C ++

(O .hxx, o .hh o altro)

Questa intestazione è solo per C ++.

Se sei in un modulo C, non provare nemmeno a includerlo. Non ti piacerà, perché non viene fatto alcuno sforzo per renderlo C-friendly (troppo andrebbe perso, come il sovraccarico delle funzioni, gli spazi dei nomi, ecc. Ecc.).

.h: intestazioni C / C ++ compatibili o pure C

Questa intestazione può essere inclusa sia da una sorgente C che da una sorgente C ++, direttamente o indirettamente.

Può essere incluso direttamente, essendo protetto dalla __cplusplusmacro:

  • Ciò significa che, da un punto di vista C ++, verrà definito il codice C-compatibile extern "C".
  • Da un punto di vista C, tutto il codice C sarà chiaramente visibile, ma il codice C ++ sarà nascosto (perché non verrà compilato in un compilatore C).

Per esempio:

#ifndef MY_HEADER_H
#define MY_HEADER_H

   #ifdef __cplusplus
      extern "C"
      {
   #endif

   void myCFunction() ;

   #ifdef __cplusplus
      } // extern "C"
   #endif

#endif // MY_HEADER_H

Oppure potrebbe essere incluso indirettamente dalla corrispondente intestazione .hpp che lo racchiude nella extern "C"dichiarazione.

Per esempio:

#ifndef MY_HEADER_HPP
#define MY_HEADER_HPP

extern "C"
{
#include "my_header.h"
}

#endif // MY_HEADER_HPP

e:

#ifndef MY_HEADER_H
#define MY_HEADER_H

void myCFunction() ;

#endif // MY_HEADER_H

3
Questo è abbastanza insolito in molti progetti C ++. I file .h sono usati per cose molto non-C'ish.
einpoklum,

4
@einpoklum: Certo. Ma cerco di evitare il comportamento di "Monkey See Monkey Do". Nel caso attuale, sono disponibili entrambe le estensioni (e altre), quindi provo a farle contare. Avere questo contratto con un codice condiviso con i client è molto utile: tutti (ovvero centinaia di sviluppatori) sanno che i file ".H" devono essere utilizzati dai client utilizzando un compilatore C, quindi non c'è dubbio su cosa può andare lì o non. E tutti (compresi i client) sanno che i file ".HPP" non tenteranno mai di essere C-friendly. Tutti vincono.
paercebal,

4
@paercebal, quindi stai suggerendo .H invece di .h e .HPP su .hpp ?
Geof Sawaya,

6
@GeofSawaya: No, scusa. È un'abitudine. Quando scrivo articoli, utilizzo le estensioni in maiuscolo per differenziare i file in base al loro tipo, ad esempio "File .HPP". Ma le estensioni dei file effettivi che si trovano sul mio disco rigido sono sempre in minuscolo, anche nel nome non lo è, come "MyClass.hpp" o "module.hpp"
paercebal,

4
Grazie, @paercebal. Stavo diventando pedante
Geof Sawaya il

48

Ho sempre considerato l' .hppintestazione come una sorta di portmanteau .he .cppfile ... un'intestazione che contiene anche dettagli di implementazione.

In genere quando ho visto (e uso) .hppcome estensione, non esiste un .cppfile corrispondente . Come altri hanno già detto, questa non è una regola dura e veloce, proprio come tendo ad usare i .hppfile.


31

Non importa quale estensione usi. Uno dei due va bene.

Uso *.hper C e *.hppper C ++.


23

EDIT [suggerimento aggiunto da Dan Nissenbaum]:

Secondo una convenzione, i file .hpp vengono utilizzati quando i prototipi sono definiti nell'intestazione stessa. Tali definizioni nelle intestazioni sono utili in caso di modelli, poiché il compilatore genera il codice per ciascun tipo solo sull'istanza del modello. Pertanto, se non sono definiti nei file di intestazione, le loro definizioni non verranno risolte al momento del collegamento da altre unità di compilazione. Se il tuo progetto è solo un progetto C ++ che fa un uso pesante di modelli, questa convenzione sarà utile.

Alcune librerie di modelli che aderiscono a questa convenzione forniscono intestazioni con estensioni .hpp per indicare che non dispongono di file .cpp corrispondenti.

un'altra convenzione è usare .h per le intestazioni C e .hpp per C ++; un buon esempio sarebbe la libreria boost.

Citazione da Boost FAQ,

Le estensioni dei file comunicano il "tipo" del file, sia agli umani che ai programmi per computer. L'estensione '.h' viene utilizzata per i file di intestazione C e quindi comunica la cosa sbagliata sui file di intestazione C ++. L'uso di nessuna estensione non comunica nulla e impone l'ispezione del contenuto del file per determinare il tipo. L'uso di '.hpp' lo identifica in modo inequivocabile come file di intestazione C ++ e funziona bene nella pratica. (Rainer Deyke)


Niente di tutto ciò è vero, non fa differenza se il file è .h o .hpp quando si tratta di generazione o collegamento di codice.
Mark Ingram,

non è solo una questione di convenzioni? La libreria std C ++ fornisce tutte le sue intestazioni senza alcuna estensione. l'utilizzo di ".hpp" indica semplicemente che i prototipi sono definiti nello stesso file e che non vi sarà alcun file .cpp corrispondente.
ProgramCpp

5
Questa risposta è utile, credo, con l'eccezione che manca una frase molto semplice, ma importante: "per convenzione, non per le regole del linguaggio" (da qualche parte).
Dan Nissenbaum,

13

Di recente ho iniziato a utilizzare *.hppper le intestazioni c ++.

Il motivo è che uso emacs come editor principale ed entra automaticamente in modalità c quando carichi un *.hfile e in modalità c ++ quando carichi un *.hppfile.

A parte questo fatto, non vedo buone ragioni per scegliere *.hsopra *.hppo viceversa.


7
Personalmente, penso che l'evidenziazione C ++ sia una buona idea anche nelle intestazioni C. Sono stato su entrambi i lati della situazione in cui qualcuno vuole includere la tua intestazione C da C ++, ma usa una parola chiave C ++ come nome di parametro ...
Steve Jessop

12

Sto rispondendo a questo come promemoria, per dare punto ai miei commenti sulla risposta "user1949346" a questo stesso PO.


Quindi, come molti hanno già risposto: in entrambi i casi va bene. Seguito da enfasi delle proprie impressioni.

Come introduttivo, come anche nei precedenti commenti citati, la mia opinione è che le C++estensioni di intestazione vengano proposte .hse in realtà non vi è alcuna ragione contro di esso.

Dal momento che i documenti ISO / IEC utilizzano questa notazione di file header e nessuna corrispondenza di stringa si .hppverifica nemmeno nelle loro documentazioni linguistiche C++.

Ma ora sto cercando un motivo accettabile PERCHÉ in entrambi i casi è ok, e soprattutto perché non è soggetto del linguaggio stesso.

Quindi eccoci.

La C++documentazione (in realtà sto prendendo riferimento alla versione N3690) definisce che un'intestazione deve essere conforme alla seguente sintassi:

2.9 Nomi delle intestazioni

header-name:
    < h-char-sequence >
    " q-char-sequence "
h-char-sequence:
    h-char
    h-char-sequence h-char
h-char:
    any member of the source character set except new-line and >
q-char-sequence:
    q-char
    q-char-sequence q-char
q-char:
    any member of the source character set except new-line and "

Quindi, come possiamo estrarre da questa parte, anche il nome del file di intestazione può essere qualsiasi cosa sia valida nel codice sorgente. Tranne il contenere '\n'caratteri e in base al fatto che debba essere incluso da <>esso non è consentito contenere un >. O viceversa se è incluso da ""-include non è consentito contenere a ".

In altre parole: se hai un ambiente che supporta nomi di file come prettyStupidIdea.>, includi come:

#include "prettyStupidIdea.>"

sarebbe valido, ma:

#include <prettyStupidIdea.>>

sarebbe invalido. Il contrario è lo stesso.

E persino

#include <<.<>

sarebbe un nome file di intestazione includibile valido.

Anche se ciò si conformasse C++, sarebbe comunque un'idea piuttosto stupida.

Ed è anche per questo che .hppè valido.

Ma non è un risultato dei comitati che progettano le decisioni per la lingua!

Discutere sull'uso .hppè lo stesso di farlo .cc, .mmo di qualsiasi altra cosa abbia letto in altri post su questo argomento.

Devo ammettere che non ho idea di dove sia .hpparrivato 1 , ma scommetterei che un inventore di alcuni strumenti di analisi, IDE o qualcos'altro che mi riguarda è C++venuto a questa idea per ottimizzare alcuni processi interni o semplicemente per inventarne alcuni (probabilmente anche per loro necessariamente ) nuove convenzioni di denominazione.

Ma non fa parte della lingua.

E ogni volta che si decide di usarlo in questo modo. Sia perché gli piace la maggior parte o perché alcune applicazioni del flusso di lavoro lo richiedono, non è mai 2 è un requisito della lingua. Quindi chiunque dice "la pp è perché è usata con C ++", ha semplicemente torto riguardo alla definizione delle lingue.

C ++ consente qualsiasi cosa che rispetti il ​​paragrafo precedente. E se c'è qualcosa che la commissione ha proposto di usare, allora sta usando .hpoiché questa è l'estensione citata in giudizio in tutti gli esempi del documento ISO.

Conclusione:

Finché non vedi / senti alcun bisogno di usare .hover .hppo viceversa, non dovresti preoccuparti. Perché entrambi formerebbero un nome di intestazione valido della stessa qualità rispetto allo standard. E quindi tutto ciò che RICHIEDE di usare .ho .hppè una restrizione aggiuntiva dello standard che potrebbe persino essere in contraddizione con altre restrizioni aggiuntive non conformi tra loro. Ma poiché OP non menziona alcuna restrizione linguistica aggiuntiva, questa è l'unica risposta corretta e approvabile alla domanda

" * .h o * .hpp per le definizioni della classe " è:

Entrambi sono ugualmente corretti e applicabili purché non siano presenti restrizioni esterne.


1 Da quello che so, a quanto pare, è il framework boost che è venuto fuori con quell'estensione .hpp.

2 Naturalmente non posso dire cosa ci porteranno alcune versioni future!


7

Preferisco .hpp per C ++ per chiarire sia agli editor che agli altri programmatori che si tratta di un'intestazione C ++ piuttosto che di un file di intestazione C.


6

C ++ ("C Plus Plus") ha senso come .cpp

Avere file header con estensione .hpp non ha lo stesso flusso logico.


6

Puoi chiamare le tue inclusioni come preferisci.

Devo solo specificare quel nome completo in #include.

Suggerisco che se lavori con C da usare .he quando con C ++ da usare .hpp.

Alla fine è solo una convenzione.


5

Codegear C ++ Builder utilizza .hpp per i file di intestazione generati automagicamente dai file sorgente di Delphi e file .h per i tuoi "propri" file di intestazione.

Quindi, quando scrivo un file header C ++ uso sempre .h.


5

In uno dei miei lavori nei primi anni '90, abbiamo usato rispettivamente .cc e .hh per i file sorgente e header. Lo preferisco ancora a tutte le alternative, probabilmente perché è più facile da scrivere.


5

Bjarne Stroustrup e Herb Sutter hanno una dichiarazione a questa domanda nelle loro linee guida C ++ Core disponibili su: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#S-source che si riferisce anche alle ultime modifiche nell'estensione standard (C ++ 11, C ++ 14, ecc.)

SF.1: utilizzare un suffisso .cpp per i file di codice e .h per i file di interfaccia se il progetto Y non segue già un'altra convenzione Motivo

È una convenzione di vecchia data. Ma la coerenza è più importante, quindi se il tuo progetto utilizza qualcos'altro, seguilo. Nota

Questa convenzione riflette un modello di uso comune: le intestazioni sono più spesso condivise con C per essere compilate sia in C ++ che in C, che in genere utilizza .h, ed è più facile nominare tutte le intestazioni .h invece di avere estensioni diverse solo per quelle intestazioni che sono destinate da condividere con C. D'altra parte, i file di implementazione sono raramente condivisi con C e quindi dovrebbero in genere essere distinti dai file .c, quindi di solito è meglio nominare tutti i file di implementazione C ++ con qualcos'altro (come .cpp).

I nomi specifici .h e .cpp non sono richiesti (consigliato solo come impostazione predefinita) e altri nomi sono ampiamente utilizzati. Esempi sono .hh, .C e .cxx. Utilizzare tali nomi in modo equivalente. In questo documento, ci riferiamo a .h e .cpp> come una scorciatoia per i file di intestazione e implementazione, anche se l'estensione effettiva potrebbe essere diversa.

Il tuo IDE (se ne usi uno) può avere opinioni forti sui suffissi.

Non sono un grande fan di questa convenzione perché se stai usando una libreria popolare come boost, la tua coerenza è già rotta e dovresti usare meglio .hpp.


4

Come molti hanno già menzionato, preferisco anche usare .hpp per le librerie solo intestazione che usano le classi / funzioni del modello. Preferisco usare .h per i file di intestazione accompagnati da file di origine .cpp o librerie condivise o statiche.

La maggior parte delle librerie che sviluppo sono basate su template e quindi devono essere solo header, ma quando scrivo applicazioni tendo a separare la dichiarazione dall'implementazione e finiscono con i file .h e .cpp


3

Fortunatamente è semplice.

Dovresti usare l'estensione .hpp se lavori con C ++ e dovresti usare .h per C o mescolare C e C ++.


2

Uso .h perché è quello che utilizza Microsoft e crea il suo generatore di codice. Non c'è bisogno di andare contro il grano.


non ovunque, in molti esempi (eq WINDDK) usano .hpp
marsh-wiggle il

13
Non chiamerei Microsoft "il grano" quando si tratta di C ++.
Developerbmw

@Brett è quando è il tuo lavoro. E anche se non lo è, è un compilatore maledettamente popolare.
Mark Ransom,

@MarkRansom Mi riferivo maggiormente alla storia di Microsoft sull'uso di C. IMO VC ++ è un eccellente compilatore.
Developerbmw

1
@developerbmw Direi che MSVC è il grano per i programmi Windows e GCC è il grano per i programmi * nix, personalmente. Sono quelli che molti altri compilatori per quelle piattaforme tendono a cercare di rimanere compatibili, per quanto ne sappia.
Justin Time - Ripristina Monica il

1

In "The C ++ Programming Language, Third Edition di Bjarne Stroustrup", il libro C ++ da leggere nº1, usa * .h. Quindi presumo che la migliore pratica sia usare * .h.

Tuttavia, anche * .hpp va bene!


1
Se qualcuno ha scritto un libro su qualcosa che ha imparato da altri che l'hanno imparato da un altro (forse per fortuna lo stesso) libro, scritto da qualcuno che forse aveva la fonte primaria disponibile, allora è quello che stanno facendo qualcosa ma non il segno per essendo la migliore pratica.
Dal

Solo per citare: in realtà l'ho votato. Ma l'avrei votato, se dicesse "ISO / IEC N3690" o qualsiasi altra bozza del C ++ non sia "Il linguaggio di programmazione C ++, terza edizione di Bjarne Stroustrup". Anche se questo sarebbe stato un punto valido, dal momento che non viene menzionato affatto .hppdalla lingua stessa.
Dhein

9
@zaibis sai che Bjarne Stroustrup ha inventato il C ++ giusto?
tumtumtum,

@tumtumtum: ammesso, non ne ero a conoscenza. Ma comunque, anche in quel caso, è ancora il documento del comitato, che mantiene lo standard, che è la referenza da prendere. Anche se è l'inventore della lingua, non è più una sua decisione. Quindi, sebbene ciò renda più valida questa risposta, non è ancora un ragionamento valido.
Dhein,

1

È facile per gli strumenti e gli esseri umani distinguere qualcosa . Questo è tutto.

Nell'uso convenzionale (tramite boost, ecc.), Sono in .hppparticolare le intestazioni C ++. D'altra parte, .hè per non C ++ - solo intestazioni (principalmente C). Rilevare con precisione la lingua del contenuto è generalmente difficile poiché ci sono molti casi non banali, quindi questa differenza rende spesso facile da scrivere uno strumento pronto per l'uso. Per gli umani, una volta ottenuto il convegno, è anche facile da ricordare e facile da usare.

Tuttavia, vorrei sottolineare che la convenzione stessa non sempre funziona, come previsto.

  • Non è forzato dalla specifica dei linguaggi , né C né C ++. Esistono molti progetti che non seguono la convenzione. Una volta che è necessario unirli (per mescolarli), può essere problematico.
  • .hppdi per sé non è l'unica scelta. Perché no .hho .hxx? (Sebbene comunque, di solito hai bisogno di almeno una regola convenzionale su nomi di file e percorsi.)

Personalmente uso entrambi .he .hppnei miei progetti C ++. Non seguo la convenzione sopra perché:

  • Le lingue utilizzate da ciascuna parte dei progetti sono esplicitamente documentate. Nessuna possibilità di mescolare C e C ++ nello stesso modulo (directory). Ogni libreria di terze parti è tenuta a conformarsi a questa regola.
  • Sono inoltre documentate le specifiche linguistiche conformi e i dialetti di lingua consentiti utilizzati dai progetti. (In effetti, documento persino l'origine delle funzionalità standard e la correzione di bug (sullo standard di lingua) in uso .) Questo è un po 'più importante che distinguere le lingue utilizzate poiché è troppo soggetto a errori e il costo del test (ad es. compatibilità del compilatore) può essere significativo (complicato e richiede molto tempo), specialmente in un progetto che è già in C ++ quasi puro . I nomi dei file sono troppo deboli per gestirlo.
  • Anche per lo stesso dialetto C ++, potrebbero esserci proprietà più importanti adatte alla differenza. Ad esempio, vedere la convenzione di seguito.
  • I nomi dei file sono essenzialmente pezzi di fragili metadati. La violazione della convenzione non è così facile da rilevare. Per essere stabili nel gestire il contenuto, uno strumento alla fine non dovrebbe dipendere solo dai nomi. La differenza tra le estensioni è solo un suggerimento. Anche gli strumenti che lo utilizzano non dovrebbero comportarsi sempre allo stesso modo, ad esempio il rilevamento della lingua dei .hfile su github.com. (Potrebbe esserci qualcosa nei commenti come shebang perché questi file sorgente siano metadati migliori, ma non è nemmeno convenzionale come i nomi dei file, quindi non è affidabile in generale.)

Di solito lo uso .hppsu header C ++ e gli header dovrebbero essere usati (mantenuti) in un modo solo header , ad esempio come librerie template. Per le altre intestazioni in .h, è presente un .cppfile corrispondente come implementazione o è un'intestazione non C ++. Quest'ultimo è banale distinguere i contenuti dell'intestazione dagli umani (o dagli strumenti con metadati espliciti incorporati, se necessario).


0

L'estensione del file sorgente potrebbe avere un significato per il tuo sistema di compilazione, ad esempio potresti avere una regola nel tuo makefile .cppo .cfile, oppure il tuo compilatore (ad esempio Microsoft cl.exe) potrebbe compilare il file come C o C ++ a seconda dell'estensione.

Poiché è necessario fornire l'intero nome file alla #includedirettiva, l'estensione del file di intestazione è irrilevante. .cSe lo desideri, puoi includere un file in un altro file sorgente, perché è solo un'inclusione testuale. Il compilatore potrebbe avere un'opzione per scaricare l'output preelaborato che lo chiarirà (Microsoft: /Ppreelaborare il file, /Epreelaborare stdout, /EPomettere le #linedirettive, /Cconservare i commenti)

È possibile scegliere di utilizzare .hppfile rilevanti solo per l'ambiente C ++, ovvero che utilizzano funzionalità che non verranno compilate in C.


0

Non vi è alcun vantaggio in nessuna particolare estensione, a parte quello che può avere un significato diverso per te, il compilatore e / o i tuoi strumenti. header.hè un'intestazione valida. header.hppè un'intestazione valida. header.hhè un'intestazione valida. header.hxè un'intestazione valida. h.headerè un'intestazione valida. this.is.not.a.valid.headerè un'intestazione valida nel rifiuto. ihjkflajfajfklafè un'intestazione valida. Finché il compilatore può analizzare correttamente il nome e il file system lo supporta, è un'intestazione valida e l'unico vantaggio della sua estensione è ciò che si legge in esso.

Detto questo, essere in grado di formulare con precisione ipotesi basate sull'estensione è molto utile, quindi sarebbe saggio utilizzare un insieme di regole facilmente comprensibili per i file di intestazione. Personalmente, preferisco fare qualcosa del genere:

  1. Se esistono già delle linee guida stabilite, seguirle per evitare confusione.
  2. Se tutti i file di origine nel progetto sono nella stessa lingua, utilizzare .h. Non c'è ambiguità.
  3. Se alcune intestazioni sono compatibili con più lingue, mentre altre sono compatibili solo con una sola lingua, le estensioni si basano sulla lingua più restrittiva con cui un'intestazione è compatibile. Un'intestazione compatibile con C, o con entrambi C & C ++, ottiene .h, mentre un'intestazione compatibile con C ++ ma non C ottiene .hppo .hho qualcosa del genere.

Questo, ovviamente, non è che uno dei tanti modi per gestire le estensioni e non puoi necessariamente fidarti della tua prima impressione anche se le cose sembrano semplici. Ad esempio, ho visto la menzione dell'utilizzo .hper le intestazioni normali e .tppper le intestazioni che contengono solo definizioni per le funzioni dei membri della classe di modelli, con i .hfile che definiscono le classi di modelli, inclusi i .tppfile che definiscono le loro funzioni dei membri (anziché l' .hintestazione che contiene direttamente entrambi i dichiarazione di funzione e la definizione). Per un altro esempio, molte persone riflettono sempre il linguaggio dell'intestazione nella sua estensione, anche quando non c'è possibilità di ambiguità; per loro, .hè sempre un'intestazione C e .hpp(o .hh, o.hxx, ecc.) è sempre un'intestazione C ++. E ancora, alcune persone usano .hper "intestazione associata a un file sorgente" e .hppper "intestazione con tutte le funzioni definite in linea".

Considerando ciò, il vantaggio principale risiederebbe nel nominare coerentemente le intestazioni nello stesso stile e nel rendere quello stile facilmente visibile a chiunque stia esaminando il codice. In questo modo, chiunque abbia familiarità con il tuo solito stile di codifica sarà in grado di determinare ciò che intendi con una determinata estensione con una rapida occhiata.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.