I file di intestazione sono effettivamente validi? [chiuso]

19

Trovo che i file di intestazione siano utili quando si esplorano i file di origine C ++, perché forniscono un "riepilogo" di tutte le funzioni e i membri dei dati in una classe. Perché così tanti altri linguaggi (come Ruby, Python, Java, ecc.) Non hanno una funzionalità come questa? Questa è un'area in cui la verbosità del C ++ è utile?

    
posta Matt Fichman 29.12.2012 - 05:31
fonte

7 risposte

29

Lo scopo originale dei file di intestazione era quello di consentire la compilazione e la modularità a passaggio singolo in C. Dichiarando i metodi prima che venissero utilizzati, consentiva solo un singolo passaggio di compilazione. Questa età è lontana da tempo grazie ai potenti computer che sono in grado di eseguire la compilazione multi-pass senza problemi e talvolta persino più veloci dei compilatori C ++.

C ++ è retrocompatibile con C necessario per mantenere i file di intestazione, ma ha aggiunto molto su di essi, il che ha portato a una progettazione piuttosto problematica. Altro in FQA .

Per modularità, i file di intestazione erano necessari come metadati sul codice nei moduli. Per esempio. quali metodi (e in classi C ++) sono disponibili in quale libreria. Era ovvio che lo sviluppatore scrivesse questo, perché il tempo di compilazione era costoso. Oggigiorno, non è un problema avere il compilatore generare questi metadati dal codice stesso. I linguaggi Java e .NET lo fanno normalmente.

Quindi no. I file di intestazione non sono buoni. Erano quando dovevamo ancora compilatore e linker su floppy separati e la compilazione richiedeva 30 minuti. Al giorno d'oggi, si mettono in mezzo e sono segno di un cattivo design.

    
risposta data 29.12.2012 - 08:37
fonte
17

Sebbene possano essere utili per te come forma di documentazione, il sistema che circonda i file di intestazione è straordinariamente inefficiente.

C è stato progettato in modo che ogni passaggio di compilazione costruisca un singolo modulo; ogni file sorgente è compilato in una sessione separata del compilatore. I file di intestazione, d'altra parte, vengono iniettati in quella fase di compilazione per ciascuno dei file sorgente che li fanno riferimento.

Questo significa che se il tuo file di intestazione è incluso in 300 file sorgente, viene analizzato e compilato ripetutamente, 300 volte separate durante la creazione del programma. La stessa identica cosa con lo stesso identico risultato, ancora e ancora. Si tratta di un enorme spreco di tempo ed è uno dei motivi principali per cui i programmi C e C ++ richiedono così tanto tempo per essere costruiti.

Tutte le lingue moderne evitano intenzionalmente questa assurda piccola inefficienza. Invece, tipicamente in linguaggi compilati, i metadati necessari vengono memorizzati all'interno dell'output di compilazione, consentendo al file compilato di agire come una sorta di riferimento rapido che descrive cosa contiene il file compilato. Tutti i vantaggi di un file di intestazione, creati automaticamente senza alcun lavoro aggiuntivo da parte tua.

Alternativamente nelle lingue interpretate, ogni modulo che viene caricato rimane in memoria. Il riferimento o l'inclusione o la richiesta di alcune librerie leggerà e compilerà il codice sorgente associato, che rimane residente fino alla fine del programma. Se lo richiedi anche altrove, nessun lavoro aggiuntivo poiché è già stato caricato.

In entrambi i casi, è possibile "sfogliare" i dati creati da questo passaggio utilizzando gli strumenti del linguaggio. In genere l'IDE avrà un browser di classe di qualche tipo. E se la lingua ha un REPL, può anche essere spesso utilizzata per generare un riepilogo della documentazione di qualsiasi oggetto caricato.

    
risposta data 29.12.2012 - 09:24
fonte
7

Non è chiaro su cosa intendi sfogliando il file per funzioni e membri dei dati. Tuttavia, la maggior parte degli IDE fornisce Strumenti per sfogliare la classe e vedere i membri dei dati della classe.

Ad esempio: Visual Studio ha Class View e Object browser che fornisce in modo bello la funzionalità richiesta. Come nelle seguenti schermate.

    
risposta data 29.12.2012 - 05:50
fonte
4

Uno svantaggio aggiuntivo dei file di intestazione è che il programma dipende dall'ordine di inclusione e il programmatore deve prendere ulteriori misure per garantire la correttezza.

Questo, insieme al sistema macro di C (ereditato da C ++), porta a molte insidie e situazioni confuse.

Per illustrare, se un'intestazione definisce un simbolo usando macro per il suo uso e un'altra intestazione usa il simbolo in un altro modo, come un nome per una funzione, allora l'ordine di inclusione influenzerebbe notevolmente il risultato finale. Ci sono molti esempi di questo tipo.

    
risposta data 24.03.2014 - 17:44
fonte
2

Mi sono sempre piaciuti i file header in quanto forniscono una forma di interfaccia all'implementazione, insieme ad alcune informazioni extra come le variabili di classe, il tutto in un unico file di facile visualizzazione.

Vedo un sacco di codice C # (che non ha bisogno di 2 file per classe) scritto usando 2 file per classe - uno per l'implementazione della classe reale e un altro con un'interfaccia al suo interno. Questo design è utile per il mocking (essenziale in alcuni sistemi) e aiuta a definire la documentazione della classe senza dover utilizzare l'IDE per visualizzare i metadati compilati. Andrei così lontano per dire che è una buona pratica.

Quindi C / C ++ che impone un equivalente (di sorta) di un'interfaccia nei file di intestazione è una buona cosa.

So che ci sono sostenitori di altri sistemi a cui non piacciono per ragioni che includono "è più difficile codificare il codice se si devono mettere le cose in 2 file", ma il mio atteggiamento è che il solo hacking del codice non è buona pratica comunque, e una volta che inizi a scrivere / progettare il codice con un po 'più di riflessione, allora definirai le intestazioni / interfacce naturalmente.

    
risposta data 29.12.2012 - 19:27
fonte
1

In realtà direi che i file di intestazioni non sono grandi perché infangano l'interfaccia e l'implementazione. L'intento con la programmazione in generale e in particolare l'OOP è di avere un'interfaccia definita e nascondere i dettagli dell'implementazione, ma un file di intestazione C ++ mostra sia i metodi, l'ereditarietà e i membri pubblici (interfaccia) che i metodi privati e i membri privati (parte dell'attuazione). Per non parlare del fatto che in alcuni casi si finisce con l'inlining del codice o dei costruttori nel file di intestazione e alcune librerie includono il codice del template nelle intestazioni, che mescola davvero l'implementazione con l'interfaccia.

L'intento originale, credo, era di rendere possibile che il codice usasse altre librerie, oggetti, ecc. senza dover importare l'intero contenuto dello script. Tutto ciò di cui hai bisogno è l'intestazione da compilare e collegare. Fa risparmiare tempo e va in questo modo. In questo caso, è un'idea decente, ma è solo un modo per risolvere questi problemi.

Per quanto riguarda la navigazione nella struttura del programma, la maggior parte degli IDE fornisce quell'abilità, e ci sono molti strumenti che daranno il via alle interfacce, fare analisi del codice, decompilazione, ecc. in modo da poter vedere cosa succede sotto le copertine.

Per quale motivo altre lingue non implementano la stessa funzione? Bene, perché altri linguaggi provengono da altre persone e quei designer / creatori hanno una visione diversa di come dovrebbero funzionare le cose.

La risposta migliore è quella di attenersi a ciò che fa il lavoro che devi fare e ti rende felice.

    
risposta data 29.12.2012 - 05:59
fonte
0

In molti linguaggi di programmazione, quando un programma è suddiviso in più unità di compilazione, il codice in una unità sarà in grado di utilizzare solo le cose definite in un'altra se il compilatore ha qualche mezzo per sapere quali sono queste cose. Anziché richiedere che un compilatore che elabora un'unità di compilazione esamini l'intero testo di ogni unità di compilazione che definisce qualcosa utilizzato all'interno dell'unità presente, è meglio che il compilatore riceva, mentre elabora ogni unità, il testo completo dell'unità da compilare lungo con poche informazioni da tutti gli altri.

In C, il programmatore è responsabile della creazione di due file per ogni unità: una contenente informazioni che saranno necessarie solo quando si compila quell'unità e una contenente le informazioni che saranno anche necessarie quando si compilano altre unità. Questo è un design piuttosto brutto, hacky, ma evita la necessità di disporre di uno standard di linguaggio che specifichi qualcosa su come i compilatori dovrebbero generare ed elaborare qualsiasi file intermedio. Molte altre lingue usano un approccio diverso, in cui un compilatore genererà da ciascun file sorgente un file intermedio che descrive tutto in quel file sorgente che dovrebbe essere accessibile al codice esterno. Questo approccio evita la necessità di avere informazioni duplicate in due file sorgente, ma richiede che una piattaforma di compilazione abbia definito la semantica dei file in un modo non richiesto per C.

    
risposta data 04.05.2015 - 20:21
fonte

Leggi altre domande sui tag