Que faire si je déteste les fichiers d'en-tête C ++?

25

J'étais toujours confus au sujet des fichiers d'en-tête. Ils sont tellement étranges: vous incluez un fichier .h qui n'inclut pas .cpp mais .cpp sont en quelque sorte compilés aussi.

Récemment, j'ai rejoint un projet d'équipe et, bien sûr, les deux .h et .cpp sont utilisés.
Je comprends que cela est très important, mais je ne peux pas vivre avec le copier-coller de chaque déclaration de fonction dans chacune des multiples classes que nous avons.

Comment gérer efficacement la convention des 2 fichiers?
Existe-t-il des outils pour vous aider ou changer automatiquement un fichier qui ressemble à l'exemple ci-dessous en .h et .cpp? (spécifiquement pour MS VC ++ 2010)

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

Type f(Type a)
{
     //implementation here
}
...
Oleh Prypin
la source
8
Cette question pourrait prendre plusieurs formes. "Pourquoi avons-nous besoin d'en-têtes lors de l'utilisation de c ++" ou, "Pensez-vous qu'un langage moderne destiné à être compilé devrait utiliser des en-têtes?" En l'état, il y a «Que dois-je faire» et «haine» dans le titre, ce qui déclenche une pléthore de drapeaux.
Tim Post
4
Votre question donne l'impression que vous ne comprenez pas le C ++, ou comment le système que vous utilisez le compile. Apprenez à l'utiliser correctement, puis posez des questions plus subjectives.
David Thornley
31
Votre première phrase indique que vous ne "comprenez pas tout sur les en-têtes". L'inclusion d'un fichier .h n'entraîne pas la "compilation en quelque sorte" du fichier .cpp correspondant. Vous compilez les fichiers .cpp indépendamment de leur propre chef. Si vous n'avez pas compilé le .cpp correspondant, alors l'inclusion d'un en-tête sans un fichier objet correspondant entraînera l'échec de l'éditeur de liens.
Paul Butcher
5
Que faire? Trouvez une autre langue si cela vous dérange autant.
Paul Nathan
5
À propos du "ne peut pas vivre avec le copier-coller": chaque fois que l'on met à jour une fonction, il faut de toute façon mettre à jour tous les endroits où elle est appelée. Comme les appelants sont beaucoup plus difficiles à trouver que la déclaration dans le fichier d'en-tête, la mise à jour de l'en-tête n'est qu'un détail mineur.
Sjoerd

Réponses:

15

Rédaction de C ++ plus convivial

En C ++, vous n'avez pas du tout besoin d'utiliser des en-têtes. Vous pouvez définir l'objet entier dans un seul fichier comme vous le feriez avec C # ou Java. Les développeurs C ne conserveront généralement les appels externes que dans un fichier d'en-tête. Tous les appels internes seraient définis dans le fichier .c. De la même manière, vous pouvez réserver vos fichiers C ++ .h pour les classes / interfaces (classes abstraites virtuelles pures) / etc. qui sont destinés à être partagés en dehors de la DLL. Pour les classes / structures / interfaces internes, etc., vous incluriez simplement le fichier .cpp dont vous avez besoin:

#include<myclass.cpp>

Cela ne semble pas être l'approche la plus populaire, mais c'est du C ++ légal. Ce serait certainement une possibilité pour tout votre code interne. Cela permet au code interne et à l'ensemble de classes de changer beaucoup plus radicalement tout en offrant une interface plus stable pour le code en dehors de votre bibliothèque / exécutable avec lequel interagir.

Le fait d'avoir toute votre classe dans un seul fichier vous permettra de faire plus facilement ce que vous voulez. Cela ne résoudra pas le problème de renommer une méthode et d'avoir à rechercher chaque endroit où cette méthode est appelée, mais cela vous assurera d'avoir des messages d'erreur plus intelligibles. Rien de pire que d'avoir votre en-tête déclarer une méthode dans un sens, mais vous l'implémentez différemment. L'autre code qui appelle le fichier d'en-tête se compilera correctement et vous obtiendrez une exception de lien, tandis que le fichier d'implémentation sera celui qui se plaint que la méthode n'a pas été définie. Lorsque vous définissez chaque méthode en place (dans la déclaration de classe réelle), vous obtiendrez le même message d'erreur quel que soit le fichier qui l'inclut.

Vous pouvez également vous pencher sur cette question: bons outils de refactoring pour C ++

Comment C / C ++ résout les fichiers d'en-tête / d'implémentation

Au niveau C de base (et C ++ est construit sur cette base), les fichiers d'en-tête déclarent la promesse d'une fonction / struct / variable qui est suffisante pour permettre à un compilateur de créer le fichier objet. De même, les fichiers d'en-tête C ++ déclarent la promesse de fonctions, de structures, de classes, etc. C'est cette définition que le compilateur utilise pour réserver de l'espace dans la pile, etc.

Les fichiers .c ou .cpp ont l'implémentation. Comme le compilateur convertit chaque fichier d'implémentation en un fichier objet, il existe des crochets pour les concepts non implémentés (ce qui a été déclaré dans l'en-tête). L'éditeur de liens lie les crochets aux implémentations dans d'autres fichiers objets et crée un binaire plus grand qui inclut tout le code (bibliothèque partagée ou exécutable).

VS spécifique

En ce qui concerne l'utilisation de ceux de Visual Studio, il existe des assistants qui facilitent un peu les choses. Le nouvel assistant de classe créera votre paire correspondante d'en-têtes et de fichiers d'implémentation. Il existe même une fonction de navigateur de classe qui vous permettra de déclarer de nouvelles méthodes. Il injectera la définition dans l'en-tête et le talon d'implémentation dans le fichier .cpp. Visual Studio possède ces fonctionnalités depuis plus d'une décennie (aussi longtemps que je les ai utilisées).

Berin Loritsch
la source
Le problème est que je modifie constamment les classes, pas seulement en ajoutant de nouvelles fonctions, etc.
Oleh Prypin
5
@BlaXpirit: Alors, pourquoi modifiez-vous constamment les classes? L'une des idées derrière la conception OO est d'avoir beaucoup de blocs de construction assez stables. Si je modifiais fortement les classes, j'aimerais un langage plus dynamique, comme Common Lisp ou Python.
David Thornley
2
C'est ce que je suis en train de faire.
J'améliore
C ++ n'a jamais été refactoring amical. Le concept de refactoring n'a pas pris de l'ampleur jusqu'à ce qu'il y ait des outils qui le rendent vraiment facile à faire dans les IDE Java. REMARQUE: ces fonctionnalités étaient disponibles pour les développeurs Smalltalk et d'autres langages, mais elles ne sont devenues courantes que lorsqu'elles étaient disponibles pour beaucoup de gens. Jusqu'à présent, je n'ai pas encore vu quelqu'un implémenter intelligemment cela pour C ++. Peut-être Resharper de JetBrains? Je sais qu'il fait du code C # et VB, mais je ne sais pas si cela vous donnera un refactoring C ++.
Berin Loritsch
@Berin: Je suis allé chercher des outils de refactoring C ++ il y a un an ou deux, et j'ai trouvé deux choses. Ils étaient assez chers à l'époque, et je n'ai pas vu de versions d'essai, donc je ne sais pas ce qu'ils ont fait. De plus, on ne travaillait qu'avec emacs, ce qui limiterait son efficacité dans une boutique Visual Studio.
David Thornley
13

Devenez développeur Java.

Si vous devez vraiment continuer à développer en C ++, vous pouvez essayer d'utiliser un IDE. Souvent, ils offrent un mécanisme par lequel vous pouvez ajouter une méthode à une classe, et il place automatiquement la déclaration dans le fichier .h et la définition dans le fichier .cpp.

Paul Butcher
la source
2
kthx, je connais un peu Java, mais vous ne pouvez pas créer de DLL Win32 de bas niveau avec lui, n'est-ce pas?
Oleh Prypin
41
Je ne sais pas pourquoi, mais «Devenir développeur Java» ressemble en quelque sorte à une insulte: D.
Oliver Weiler
2
Si vous voulez faire du bas niveau, oubliez tout sur les «langues faciles». Un faible niveau coûte de la sueur et des larmes.
Batibix
5
Pas une réponse particulièrement utile.
ChrisF
1
@OliverWeiler Je ne perçois pas "devenir un développeur Java" comme une insulte. Je programme à la fois en C ++ et Java, mais ma préférence est de loin Java parce qu'il est beaucoup plus facile de s'asseoir et de frapper du code qui fonctionne (et plus portable). Si, pour une raison quelconque, vous détestez l'existence de fichiers d'en-tête, essayer Java peut être le bon choix (bien qu'il soit étrange que vous détestiez les fichiers d'en-tête; j'envisagerais un changement d'IDE).
Trixie Wolf
7

Vous pourriez être intéressé par le programme makeheaders de Hwaci (ceux qui font SQLite et Fossil).

Regardez également comment les fossiles sont construits pour avoir une idée.

Benoit
la source
5
Le demandeur doit encore bien comprendre la relation entre .h et .cpp.
Job
2
Je comprends les bases. La réponse semble être exactement ce dont j'ai besoin.
Oleh Prypin
4

Lorsque vous écrivez les premières lignes d'une nouvelle classe, c'est généralement parce que vous en avez besoin au même endroit à ce moment-là. Plus tard, il pourrait être utilisé à plus d'endroits, mais initialement ce n'est généralement pas le cas.

Beaucoup de mes cours commencent en haut du fichier .cpp actuel. Quand il a suffisamment stabilisé pour l'utiliser à plusieurs endroits, je le coupe-collez dans un en-tête. Bien que souvent la classe disparaisse aussi vite qu'elle est apparue.

Sjoerd
la source
-1

Comme suggestion pour aider à gérer les fichiers d'en-tête C ++, il est courant de les utiliser sans extension de fichier ou suffixe de fichier, comme le font les bibliothèques "GCC".

Si tel est votre cas, je suggère d'utiliser une extension de fichier ou un suffixe de fichier " .hpp" (ou moins " .hxx").

Vous devrez peut-être configurer votre compilateur, l'environnement de développement ou le programme Built.

umlcat
la source
3
Parlez-vous de la façon dont vous incluez un fichier comme #include <iostream>? Ce ne sont pas seulement pour la bibliothèque GCC. En fait, il est défini dans la norme C ++ de 1997 , section 17.3.1.2. J'éviterais de nommer des fichiers comme ça. Vous pouvez, mais la raison pour laquelle la bibliothèque standard C ++ l'a fait était probablement pour éviter les conflits de noms. En fait, je trouve ça vraiment bizarre lorsque les compilateurs ajoutent automatiquement un «.h» lorsque vous incluez un en-tête, cela me semble assez standard. Et je ne vois jamais d'en-têtes de noms sans suffixe, à l'exception de la bibliothèque standard c ++.
vedosity
1
De plus, je dois noter que tous les compilateurs que j'ai utilisés, à l'exception de borland (que je déteste tellement), n'ajoutent pas automatiquement un '.h' ou '.hpp' ou '.hxx' lorsque vous essayez pour inclure un fichier sans suffixe. Ne vous attendez pas #include <someclass>à être lu comme #include <someclass.hpp>sur tous les compilateurs. Votre code va casser.
vedosity