Pourquoi avons-nous besoin d'insérer des députés dans les en-têtes?

62

Les variables privées sont un moyen de masquer la complexité et les détails d'implémentation à l'utilisateur d'une classe. C'est une fonctionnalité plutôt intéressante. Mais je ne comprends pas pourquoi en c ++ nous devons les mettre dans l’en-tête d’une classe. Je vois deux inconvénients ennuyeux à ceci:

  • Il encombre l'en-tête de l'utilisateur
  • Il force la recompilation de toutes les bibliothèques clientes chaque fois que les internes sont modifiés

Y a-t-il une raison conceptuelle derrière cette exigence? Est-ce seulement pour faciliter le travail du compilateur?

Simon Bergot
la source
vous pouvez déclarer une structure vide dans l'en-tête, mais vous ne pouvez alors utiliser des pointeurs vers une telle structure que lorsque vous l'utilisez (et vous ne pouvez pas en affecter un)
fratchet freak
3
@ratchetfreak: Non, la méthode empty ( struct foo{};) n'est pas autorisée, mais les déclarations forward ( struct foo;) le sont.
MSalters
@MSalters c'est ce que je voulais dire
rochet
1
Ajoutons un inconvénient: * Écrire des en-têtes de fonction privées dans le fichier .h est une énorme perte de temps. (oubliant un cours d'amis pour un moment)
Jonny

Réponses:

68

C'est parce que le compilateur C ++ doit connaître la taille réelle de la classe pour pouvoir allouer la bonne quantité de mémoire lors de l'instanciation. Et la taille inclut tous les membres, même les membres privés.

Une façon d'éviter cela consiste à utiliser le langage Pimpl , expliqué par Herb Sutter dans ses séries 24 et 28 de Guru of the Week .

Mise à jour

En effet, ce (ou plus généralement, la distinction de fichier en- tête / source et #includes) est un obstacle majeur en C ++, héritée de C. Retour dans les jours C ++ C a été créé, il n'y avait pas encore d' expérience avec un grand développement de logiciels à grande échelle, où cette commence à causer de vrais problèmes. Les concepteurs de langages plus récents ont pris en compte les leçons apprises depuis, mais C ++ est soumis à des exigences de compatibilité ascendante, ce qui rend très difficile la résolution d'un problème aussi fondamental dans le langage.

Péter Török
la source
Ce type d'informations ne figure-t-il pas uniquement dans la bibliothèque de classes? Est-il utilisé pour la liaison?
Simon Bergot
@ Simon, qu'entendez-vous par "bibliothèque de classes"?
Péter Török
Je parle de la collection de fichiers objets contenant la définition et les méthodes de la classe
Simon Bergot
7
Lors de la création du C ++, AT & T / Bell Labs (employeur de Stroustrups à l’époque) avait certainement de l’expérience dans le développement du C à grande échelle. Leur logiciel de commutation téléphonique 5ESS était probablement le programme C le plus important au monde. Les premières idées sur OO sont déjà visibles dans cette base de code, et Cfront a imité ces techniques. Cependant, la notion de privateest plus moderne.
MSalters
1
En C, vous placeriez simplement l'allocateur dans une fonction de bibliothèque; le client ne pourrait pas allouer une telle structure du tout. Cela augmente légèrement les frais généraux, mais rend la migration du code entre les versions facile, ce qui en vaut souvent la peine. Cependant, cela a tendance à conduire à un style de code très différent de celui du C ++.
Donal Fellows
15

La définition de la classe doit être suffisante pour que le compilateur produise une disposition identique en mémoire partout où vous avez utilisé un objet de la classe. Par exemple, étant donné quelque chose comme:

class X { 
    int a;
public:
    int b;
};

Le compilateur aura généralement aau décalage 0 et bau décalage 4. Si le compilateur voyait cela simplement:

class X { 
public:
    int b;
};

Il "penserait" que ble décalage 0 doit être remplacé par le décalage 4. Lorsque le code utilisant cette définition est attribué à b, le code utilisant la première définition aest modifié, et inversement.

Le moyen habituel de minimiser les effets des modifications apportées aux parties intimes de la classe est généralement appelé idiome de pimpl (sur lequel, j'en suis sûr, Google peut fournir beaucoup d'informations).

Jerry Coffin
la source
1
Je parle d'une décision de conception. Bien sûr, vous auriez besoin de placer la déclaration d'initiative privée quelque part pour que la langue fonctionne. Mais pourquoi devrait-il figurer dans l'en-tête et non dans un endroit plus privé?
Simon Bergot
7
@Simon: L'en-tête est tout ce que le compilateur voit pour lui dire à quoi ressemble la classe / struct. Il a été question d'ajouter quelque chose comme des modules au C ++, ce qui masquerait un peu plus ce type de données, mais jusqu'à présent, elles n'ont pas été approuvées (bien qu'elles n'aient pas non plus été complètement supprimées).
Jerry Coffin
3
Néanmoins, une règle triviale consisterait à allouer en dernier ces membres privés "définis par .cpp". Cela signifie que les compensations des députés publics et des députés "normaux" ne dépendraient pas d’eux. IMO, la vraie raison est que vous ne pouvez pas hériter d'une telle classe, car la partie dérivée doit suivre même les membres privés.
MSalters
3

Il y a probablement plusieurs raisons. Bien que la plupart des autres classes ne puissent accéder aux membres privés, les classes d'amis peuvent toujours y accéder. Donc, au moins dans ce cas, ils peuvent être nécessaires dans l'en-tête afin que la classe friend puisse voir qu'ils existent.

La recompilation des fichiers dépendants peut dépendre de votre structure d'inclusion. L'inclusion des fichiers .h dans un fichier .cpp au lieu d'un autre en-tête peut dans certains cas empêcher de longues chaînes de recompilations.

Thorsten Müller
la source