Wat moet er in een .h-bestand?

Als je je code opsplitst in meerdere bestanden, wat moet er dan precies in een .h-bestand en wat in een .cpp-bestand?


Antwoord 1, autoriteit 100%

Headerbestanden (.h) zijn ontworpen om de informatie te leveren die nodig is in meerdere bestanden. Dingen zoals klassedeclaraties, functie-prototypes en opsommingen gaan meestal in header-bestanden. Kortom, “definities”.

Codebestanden (.cpp) zijn ontworpen om de implementatie-informatie te leveren die slechts in één bestand bekend hoeft te zijn. Over het algemeen horen functie-elementen en interne variabelen die wel/nooit door andere modules moeten worden benaderd, in .cpp-bestanden. Kortom, “implementaties”.

De eenvoudigste vraag die je jezelf moet stellen om te bepalen wat waar hoort, is “als ik dit verander, moet ik dan de code in andere bestanden wijzigen om dingen opnieuw te compileren?” Als het antwoord “ja” is, hoort het waarschijnlijk in het headerbestand; als het antwoord “nee” is, hoort het waarschijnlijk in het codebestand.


Antwoord 2, autoriteit 47%

Feit is dat dit in C++ iets gecompliceerder is dan de C-header/bronorganisatie.

Wat ziet de compiler?

De compiler ziet één groot bronbestand (.cpp) met de juiste headers erbij. Het bronbestand is de compilatie-eenheid die wordt gecompileerd tot een objectbestand.

Dus, waarom zijn headers nodig?

Omdat de ene compilatie-eenheid informatie nodig kan hebben over een implementatie in een andere compilatie-eenheid. Men kan dus bijvoorbeeld de implementatie van een functie in de ene bron schrijven, en de verklaring van deze functie in een andere bron schrijven om deze te gebruiken.

In dit geval zijn er twee exemplaren van dezelfde informatie. Wat is slecht…

De oplossing is om wat details te delen. Hoewel de implementatie in de bron moet blijven, moet de declaratie van gedeelde symbolen, zoals functies, of definitie van structuren, klassen, opsommingen, enz., mogelijk worden gedeeld.

Headers worden gebruikt om die gedeelde details te plaatsen.

Verplaats naar de kop de verklaringen van wat gedeeld moet worden tussen meerdere bronnen

Niets meer?

In C++ zijn er enkele andere dingen die in de kop kunnen worden geplaatst, omdat ze ook moeten worden gedeeld:

  • inline-code
  • sjablonen
  • constanten (meestal degene die je binnen schakelaars wilt gebruiken…)

Verplaats naar de kop ALLES wat moet worden gedeeld, inclusief gedeelde implementaties

Betekent dit dan dat er bronnen in de headers kunnen zijn?

Ja. In feite zijn er veel verschillende dingen die in een “header” kunnen staan ​​(d.w.z. gedeeld tussen bronnen).

  • Declaraties doorsturen
  • declaraties/definitie van functies/structs/klassen/sjablonen
  • implementatie van inline- en sjablooncode

Het wordt ingewikkeld en in sommige gevallen (circulaire afhankelijkheden tussen symbolen) onmogelijk om het in één kop te houden.

Headers kunnen in drie delen worden opgesplitst

Dit betekent dat u in een extreem geval het volgende zou kunnen hebben:

  • een voorwaartse aangiftekop
  • een aangifte-/definitiekop
  • een implementatiekop
  • een implementatiebron

Stel ons voor dat we een MyObject-sjabloon hebben. We hadden kunnen hebben:

// - - - - MyObject_forward.hpp - - - - 
// This header is included by the code which need to know MyObject
// does exist, but nothing more.
template<typename T>
class MyObject ;

.

// - - - - MyObject_declaration.hpp - - - - 
// This header is included by the code which need to know how
// MyObject is defined, but nothing more.
#include <MyObject_forward.hpp>
template<typename T>
class MyObject
{
   public :
      MyObject() ;
   // Etc.
} ;
void doSomething() ;

.

// - - - - MyObject_implementation.hpp - - - - 
// This header is included by the code which need to see
// the implementation of the methods/functions of MyObject,
// but nothing more.
#include <MyObject_declaration.hpp>
template<typename T>
MyObject<T>::MyObject()
{
   doSomething() ;
}
// etc.

.

// - - - - MyObject_source.cpp - - - - 
// This source will have implementation that does not need to
// be shared, which, for templated code, usually means nothing...
#include <MyObject_implementation.hpp>
void doSomething()
{
   // etc.
} ;
// etc.

Wauw!

In het ‘echte leven’ is het meestal minder ingewikkeld. De meeste code heeft alleen een eenvoudige header/bron-organisatie, met wat inline code in de bron.

Maar in andere gevallen (sjabloonobjecten die elkaar kennen), moest ik voor elk object afzonderlijke declaratie- en implementatieheaders hebben, met een lege bron inclusief die headers om me te helpen enkele compilatiefouten te zien.

Een andere reden om headers op te splitsen in afzonderlijke headers zou kunnen zijn om de compilatie te versnellen, het aantal symbolen dat wordt geparseerd te beperken tot het strikt noodzakelijke, en het vermijden van onnodige hercompilatie van een bron die alleen zorgt voor de forward-declaratie bij een inline-methode-implementatie gewijzigd.

Conclusie

U moet uw codeorganisatie zowel zo eenvoudig mogelijk als zo modulair mogelijk maken. Zet zoveel mogelijk in het bronbestand. Geef alleen in headers weer wat gedeeld moet worden.

Maar op de dag dat je cirkelvormige afhankelijkheden hebt tussen sjabloonobjecten, wees niet verbaasd als je code-organisatie wat “interessanter” wordt dan de gewone kop-/bronorganisatie…

^_^


Antwoord 3, autoriteit 16%

naast alle andere antwoorden, zal ik je vertellen wat je NIET in een headerbestand plaatst:
using-declaratie (de meest voorkomende is using namespace std;) zou niet in een headerbestand moeten verschijnen omdat ze de naamruimte vervuilen van het bronbestand waarin het is opgenomen.


Antwoord 4, autoriteit 8%

Wat tot niets wordt gecompileerd(nul binaire voetafdruk) gaat naar het headerbestand.

Variabelen compileren niet tot niets, maar typedeclaraties wel (omdat ze alleen beschrijven hoe variabelen zich gedragen).

functies niet, maar inline-functies wel (of macro’s), omdat ze alleen code produceren waar ze worden aangeroepen.

sjablonen zijn geen code, ze zijn slechts een recept voor het maken van code. dus ze gaan ook in h-bestanden.


Antwoord 5, autoriteit 4%

Over het algemeen plaatst u declaraties in het headerbestand en definities in het implementatiebestand (.cpp). De uitzondering hierop zijn sjablonen, waar de definitie ook in de kop moet komen te staan.

Deze vraag en soortgelijke vragen zijn vaak gesteld op SO – zie Waarom hebben header-bestanden en .cpp-bestanden in C++?en C++ Header Bestanden, codescheidingbijvoorbeeld.


Antwoord 6, autoriteit 2%

Voornamelijk headerbestand bevat klasseskeletof declaratie(verandert niet vaak)

en cpp-bestand bevat class-implementatie(verandert regelmatig).


Antwoord 7, autoriteit 2%

Koptekst (.h)

  • Macro’s en bijlagen die nodig zijn voor de interfaces (zo weinig mogelijk)
  • De declaratie van de functies en klassen
  • Documentatie van de interface
  • Verklaring van inline functies/methoden, indien van toepassing
  • extern voor globale variabelen (indien aanwezig)

Lichaam (.cpp)

  • Rest van macro’s en inclusief
  • Voeg de kop van de module toe
  • Definitie van functies en methoden
  • Algemene variabelen (indien aanwezig)

Als vuistregel zet je het “gedeelde” deel van de module op de .h (het deel dat andere modules moeten kunnen zien) en het “niet gedeelde” deel op de .cpp

PD: Ja, ik heb globale variabelen toegevoegd. Ik heb ze een paar keer gebruikt en het is belangrijk om ze niet in de headers te definiëren, anders krijg je een heleboel modules, die elk hun eigen variabele definiëren.


Antwoord 8, autoriteit 2%

Uw klasse- en functiedeclaraties plus de documentatie en de definities voor inline functies/methoden (hoewel sommigen ze liever in aparte .inl-bestanden plaatsen).


Antwoord 9, autoriteit 2%

het header-bestand (.h) zou moeten zijn voor declaraties van klassen, structs en zijn methoden, prototypes, enz. De implementatie van die objecten wordt gemaakt in cpp.

in .h

   class Foo {
    int j;
    Foo();
    Foo(int)
    void DoSomething();
}

Antwoord 10

Ik zou verwachten te zien:

  • verklaringen
  • opmerkingen
  • definities inline gemarkeerd
  • sjablonen

het echte antwoord is echter wat je er niet in moet zetten:

  • definities (kan ertoe leiden dat dingen meervoudig gedefinieerd worden)
  • declaraties/richtlijnen gebruiken (dwingt ze aan iedereen, inclusief je header, kan naamconflicten veroorzaken)

Antwoord 11

De kop Definieertiets, maar vertelt niets over de implementatie. ( Exclusief sjablonen in deze “metafore”.

Dat gezegd hebbende, moet je “definities” in subgroepen verdelen, in dit geval zijn er twee soorten definities.

  • Je definieert de “lay-out” van je structuur en vertelt alleen zoveel als nodig is voor de omringende gebruikersgroepen.
  • De definities van een variabele, functie en een klasse.

Nu heb ik het natuurlijk over de eerste subgroep.

De koptekst is er om de lay-out van uw structuur te definiëren, zodat de rest van de software de implementatie kan gebruiken. Je zou het misschien willen zien als een “abstractie” van je implementatie, wat grof gezegd is, maar ik denk dat het in dit geval heel goed past.

Zoals eerdere posters hebben gezegd en laten zien dat je private en publieke gebruiksgebieden en hun headers declareert, omvat dit ook private en publieke variabelen. Nu wil ik hier niet ingaan op het ontwerp van de code, maar u kunt overwegen wat u in uw headers plaatst, aangezien dat de laag is tussen de eindgebruiker en de implementatie.


Antwoord 12

  • Headerbestanden – mogen niet te vaak veranderen tijdens de ontwikkeling -> je moet nadenken en ze tegelijk schrijven (in het ideale geval)
  • Bronbestanden – wijzigingen tijdens implementatie

Other episodes