Cosa fare se odio i file di intestazione C ++?


25

Sono sempre stato confuso sui file di intestazione. Sono così strani: includi il file .h che non include .cpp ma .cpp sono in qualche modo anche compilati.

Di recente mi sono unito a un progetto di squadra e, naturalmente, sono stati utilizzati sia .h che .cpp.
Capisco che questo è molto importante, ma non posso convivere con il copia-incolla di ogni dichiarazione di funzione in ciascuna delle classi multiple che abbiamo.

Come posso gestire in modo efficiente la convenzione a 2 file?
Ci sono strumenti per aiutarlo o cambiare automaticamente un file che appare come esempio qui sotto in .h e .cpp? (specificamente per MS VC ++ 2010)

class A
{
...
    Type f(Type a,Type b)
    {
        //implementation here, not in another file!
    }
...
};

Type f(Type a)
{
     //implementation here
}
...

8
Questa domanda potrebbe andare in un paio di modi. "Perché abbiamo bisogno delle intestazioni quando si usa c ++" o "Pensi che un linguaggio moderno che dovrebbe essere compilato dovrebbe usare le intestazioni?" Così com'è, ha "Cosa devo fare" e "odio" nel titolo, che fa scattare una pletora di bandiere.
Tim Post

4
La tua domanda fa sembrare che tu non capisca il C ++ o come lo compili il sistema che usi. Impara a usarlo correttamente, quindi fai domande più soggettive.
David Thornley,

31
La tua prima frase indica che non "capisci tutto sulle intestazioni". L'inclusione di un file .h non comporta la "compilazione in qualche modo anche del file .cpp corrispondente". Compilare i file .cpp in modo indipendente. Se non hai compilato il corrispondente .cpp, l'inclusione di un'intestazione senza un file oggetto corrispondente farà fallire il linker.
Paul Butcher,

5
Cosa fare? Trova un'altra lingua se ti infastidisce così tanto.
Paul Nathan,

5
Informazioni sul "impossibile convivere con il copia-incolla": ogni volta che si aggiorna una funzione, è necessario aggiornare tutti i luoghi in cui viene chiamato comunque. Poiché i chiamanti sono molto più difficili da trovare rispetto alla dichiarazione nel file di intestazione, l'aggiornamento dell'intestazione è solo un dettaglio minore.
Sjoerd,

Risposte:


15

Scrivere più refactoring amichevole C ++

In C ++ non si deve usare le intestazioni a tutti. Puoi definire l'intero oggetto in un file come faresti con C # o Java. Gli sviluppatori C di solito mantengono le chiamate esterne in un file di intestazione. Tutte le chiamate interne sarebbero definite nel file .c. Allo stesso modo, è possibile prenotare i file .h C ++ per le classi / interfacce (classi astratte virtuali pure) / ecc. che devono essere condivisi all'esterno della DLL. Per classi / strutture / interfacce interne, ecc. Dovresti semplicemente includere il file .cpp che ti serve:

#include<myclass.cpp>

Questo non sembra essere l'approccio più popolare, ma è C ++ legale. Sarebbe sicuramente una possibilità per tutto il tuo codice interno. Ciò consente al codice interno e all'insieme di classi di cambiare molto più radicalmente fornendo al contempo un'interfaccia più stabile per il codice esterno alla libreria / eseguibile con cui interagire.

Avere tutta la classe all'interno di un file renderà più facile fare ciò che vuoi. Non risolverà il problema della ridenominazione di un metodo e la ricerca in ogni luogo chiamato quel metodo, ma assicurerà di avere messaggi di errore più comprensibili. Niente di peggio che avere l'intestazione dichiarare un metodo in un modo, ma lo implementi in modo diverso. Altro codice che chiama il file di intestazione verrà compilato correttamente e otterrai un'eccezione di collegamento, mentre il file di implementazione sarà quello che si lamenta che il metodo non è stato definito. Quando definisci tutti i metodi in atto (nella dichiarazione di classe effettiva), otterrai lo stesso messaggio di errore, indipendentemente dal file che lo include.

Potresti anche voler esaminare questa domanda: buoni strumenti di refactoring per C ++

Come C / C ++ risolve i file di intestazione / implementazione

A livello C di base (e C ++ è basato su quella base), i file di intestazione dichiarano la promessa di una funzione / struttura / variabile che è sufficiente per consentire a un compilatore di creare il file oggetto. Allo stesso modo i file di intestazione C ++ dichiarano la promessa di funzioni, strutture, classi, ecc. È questa definizione che il compilatore utilizza per riservare spazio nello stack, ecc.

I file .c o .cpp hanno l'implementazione. Mentre il compilatore converte ciascun file di implementazione in un file oggetto, ci sono hook in concetti non implementati (ciò che è stato dichiarato nell'intestazione). Il linker lega gli hook alle implementazioni in altri file oggetto e crea un file binario più grande che include tutto il codice (libreria condivisa o eseguibile).

VS specifico

Per quanto riguarda lavorare con quelli in Visual Studio, ci sono alcune procedure guidate che aiutano a rendere le cose un po 'più facili. La nuova procedura guidata di classe creerà la coppia di intestazione e file di implementazione corrispondenti. Esiste anche una funzione browser di classe che ti permetterà di dichiarare nuovi metodi. Inserirà la definizione nell'intestazione e lo stub di implementazione nel file .cpp. Visual Studio ha queste funzionalità da oltre un decennio (purché le abbia utilizzate).


Il problema è che sto costantemente modificando pesantemente le classi, non solo aggiungendo nuove funzioni, ecc.
Oleh Prypin,

5
@BlaXpirit: Quindi, perché stai modificando pesantemente le classi tutto il tempo? Una delle idee alla base del design OO è quella di avere molti blocchi costitutivi abbastanza stabili. Se stessi modificando pesantemente le classi, mi piacerebbe un linguaggio più dinamico, come Common Lisp o Python.
David Thornley,

2
È quello che sto facendo. Sto migliorando / modificando i "mattoni" e aggiungendone di nuovi
Oleh Prypin,

Il C ++ non è mai stato adatto al refactoring. Il concetto di refactoring non ha guadagnato slancio fino a quando non ci sono stati strumenti che lo hanno reso veramente facile da fare negli IDE Java. NOTA: queste funzionalità erano disponibili per gli sviluppatori Smalltalk e altre lingue, ma non sono diventate mainstream fino a quando non sono state disponibili per molte persone. Finora devo ancora vedere qualcuno che lo implementa in modo intelligente per C ++. Forse Resharper da JetBrains? So che fa codice C # e VB, ma non sono sicuro che ti darà refactoring C ++.
Berin Loritsch,

@Berin: sono andato alla ricerca di strumenti di refactoring C ++ un anno o due fa e ho trovato due cose. All'epoca erano abbastanza costosi e non ho visto le versioni di prova, quindi non so cosa abbiano fatto. Inoltre, uno ha funzionato solo con emacs, il che avrebbe limitato la sua efficacia in un negozio di Visual Studio.
David Thornley,

13

Diventa uno sviluppatore Java.

Se devi davvero continuare a sviluppare in C ++, puoi provare a utilizzare un IDE. Spesso offrono alcuni meccanismi con i quali è possibile aggiungere un metodo a una classe e posiziona automagicamente la dichiarazione nel file .h e la definizione nel file .cpp.


2
kthx, conosco un po 'Java, ma non puoi creare DLL Win32 di basso livello con esso, vero?
Oleh Prypin,

41
Non so perché, ma "Diventa uno sviluppatore Java" suona in qualche modo come un insulto: D.
Oliver Weiler,

2
Se vuoi fare un livello basso, dimentica tutto di "lingue facili". Bassi livelli di sudore e lacrime.
Batibix,

5
Non è una risposta particolarmente utile.
ChrisF

1
@OliverWeiler Non vedo "diventare uno sviluppatore Java" come un insulto. Programma sia in C ++ che in Java, ma la mia preferenza è di gran lunga Java perché è molto più facile sedersi e sbattere il codice che funziona (e più portatile). Se per qualche motivo detesti l'esistenza dei file di intestazione, provare Java potrebbe essere la scelta giusta (anche se è strano che odierai i file di intestazione; prenderei in considerazione un cambiamento nell'IDE).
Trixie Wolf,

7

Potresti essere interessato al programma makeheaders di Hwaci (quelli che fanno SQLite e Fossil).

Dai anche un'occhiata a come è costruito il fossile per avere un'idea.


5
Il richiedente deve ancora capire abbastanza bene la relazione tra .h e .cpp.
Giobbe

2
Capisco le basi. La risposta sembra essere proprio quello di cui ho bisogno.
Oleh Prypin,

4

Quando scrivi le prime righe di una nuova classe, di solito è perché ne hai bisogno in un posto solo in quel momento. In un secondo momento, potrebbe essere utilizzato in più luoghi, ma inizialmente non lo è.

Molte delle mie lezioni iniziano all'inizio del file .cpp corrente. Quando si è stabilizzato abbastanza per usarlo in più punti, lo incido in un'intestazione. Anche se spesso la classe scompare velocemente come sembrava.


-1

Come suggerimento per aiutare a gestire i file di intestazione C ++, è comune usarli senza estensione o suffisso, come fanno le librerie "GCC".

Se questo è il tuo caso, ti suggerisco di usare un'estensione di file " .hpp" (o unleast " .hxx") o un suffisso di file.

Potrebbe essere necessario configurare il compilatore, l'ambiente di sviluppo o il programma creato.


3
Stai parlando di come quando includi un file come #include <iostream>? Quelli non sono solo per la libreria GCC. In effetti, è definito nella norma C ++ del 1997 , sezione 17.3.1.2. Eviterei di nominare file del genere. È possibile, ma la ragione per cui la libreria standard C ++ lo ha fatto era probabilmente per evitare conflitti di denominazione. Lo trovo davvero strano quando i compilatori aggiungono automaticamente un '.h' quando includi un'intestazione, mi sembra piuttosto fuori standard. E non vedo mai nessuno intestazioni di nome senza suffisso tranne la libreria standard c ++.
vedosity

1
Inoltre, dovrei notare che tutti i compilatori che ho usato, tranne Borland (che odio così tanto), non aggiungono automaticamente un '.h' o '.hpp' o '.hxx' quando provi per includere un file senza suffisso. Non aspettarti #include <someclass>di essere letto come #include <someclass.hpp>su tutti i compilatori. Il tuo codice si romperà.
vedosity
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.