web-dev-qa-db-fra.com

Exemple d'en-tête privé / public?

Quelqu'un peut-il me donner un exemple du fonctionnement des en-têtes publics et privés? J'ai fait quelques lectures sur le net mais je n'arrive pas à trouver beaucoup d'informations utiles avec des exemples de codes. On m'a conseillé d'utiliser des en-têtes privés pour séparer les parties publiques et privées de mon code pour créer une bibliothèque statique. Après quelques lectures, j'ai une idée générale de son fonctionnement, mais j'apprécierais vraiment un bon exemple pour me lancer. Plus précisément, ce que je ne comprends pas très bien, c'est comment mettre les fonctions d'interface dans mon en-tête public et les variables/fonctions privées dans mon en-tête privé? Merci!

MODIFIER:

Peut-être que je ne formule pas ma question correctement, mais ce que je voulais dire, par exemple, j'ai myMath.h et myMath.cpp, et myMath.h a:

class myMath{
public:
    void initialise(double _a, double _b);
    double add();
    double subtract();

private:
    double a;
    double b;
};

Et myMath.cpp a les implémentations des fonctions. Comment puis-je faire en sorte que myMath.h ne dispose que des trois fonctions publiques et que les variables privées soient définies dans un autre fichier (par exemple myMath_i.h), et ces trois fichiers sont tels que, après avoir créé une bibliothèque statique, seul myMath.h est nécessaire aux utilisateurs. Cela signifie également que myMath.h ne peut pas #inclure myMath_i.h. Donc quelque chose comme:

myMath.h:

class myMath{
public:
    void initialise(double _a, double _b);
    double add();
    double subtract();
}

et myMath_i.h:

class myMath{
private:
    double a;
    double b;
}

Bien sûr, ce n'est pas possible car je redéfinirai la classe myMath ...

29
chocobo_ff

Vous avez deux fichiers d'en-tête MyClass.h et MyClass_p.h et un fichier source: MyClass.cpp.

Jetons un coup d'œil à leur contenu:

MyClass_p.h:

// Header Guard Here
class MyClassPrivate
{
public:
    int a;
    bool b;
    //more data members;
}

MyClass.h:

// Header Guard Here
class MyClassPrivate;
class MyClass
{
public:
    MyClass();
    ~MyClass();
    void method1();
    int method2();
private:
    MyClassPrivate* mData;
}

MyClass.cpp:

#include "MyClass.h"
#include "MyClass_p.h"

MyClass::MyClass()
{
    mData = new MyClassPrivate();
}

MyClass::~MyClass()
{
    delete mData;
}

void MyClass::method1()
{
    //do stuff
}

int MyClass::method2()
{
    return stuff;
}

Conservez vos données dans MyClassPrivate et distribuez MyClass.h.

23
erelender

Vous pouvez déclarer toutes les interfaces et constantes que vous souhaitez exposer à l'utilisateur de la bibliothèque dans un fichier d'en-tête distinct (ou un ensemble de fichiers) et le placer dans le sous-répertoire "inc" - ces en-têtes seront "publics". Vous utiliserez également d'autres fichiers d'en-tête pour déclarer les classes et les éléments que vous ne souhaitez pas exposer car ce sont des détails d'implémentation - vous placerez ces fichiers dans le sous-répertoire "src" - ceux-ci seront "privés".

De cette façon, l'utilisateur recevra un indice qu'il doit inclure uniquement les en-têtes publics - ceux qui sont en "inc" et seuls ces en-têtes contiennent les éléments dont il a vraiment besoin, tandis que tous les autres en-têtes sont "privés" et hors de son intérêt à moins qu'il ne souhaite lire dans la mise en œuvre.

Lorsque vous publiez votre bibliothèque au format binaire - bibliothèque statique ou dynamique - vous copiez uniquement le contenu "inc" et le résultat de la compilation - ceux-ci sont suffisants pour l'utilisateur et de cette façon, il ne voit pas vos sources d'implémentation.

10
sharptooth

J'ai en fait trouvé l'approche à deux en-têtes et une source fragile. Si vous oubliez de mettre à jour l'en-tête "public" après avoir modifié l'en-tête "privé", votre code peut être compilé, puis segfault ailleurs au moment de l'exécution. J'ai eu cela plusieurs fois, je préfère donc écrire du code qui ne se compilera que si tout est correct.

MyClass.cpp est implémenté comme ceci:

#define MYCLASS_IMPL
#include "MyClass.h"

// Implementation follows
...

MyClass.h est le bit intéressant:

#ifdef MYCLASS_IMPL
#include everything needed for the private: section
#endif

#include everything needed for the public: section only

class MyClass
{
public:
    // Everything that's public

#ifdef MYCLASS_IMPL
private:

    // Implementation details

#endif
};

Si l'objectif est de masquer les détails de l'implémentation (par exemple, une bibliothèque fermée), vous devrez peut-être utiliser l'approche à deux en-têtes. Si vous ne voulez pas faire glisser les dépendances uniquement pour utiliser une classe, l'approche à en-tête unique peut être une solution simple et robuste.


Pour répondre à la question d'Arton: cela fait un moment que je n'ai pas regardé cela, mais je pense que le problème était lié à l'instanciation d'objets basés sur l'en-tête public, puis à l'hypothèse d'une taille d'objet différente avec l'en-tête privé. Au moment de l'exécution, un décalage dans l'objet ne correspondrait pas, provoquant un écrasement de mémoire. Il semble que la réponse d'Erenlender couvre ce cas avec une paire de classes publique/privée.

3
Daniel Schuler

Les en-têtes publics sont ceux dont les utilisateurs de la bibliothèque ont besoin. Les en-têtes privés sont ceux nécessaires pour compiler la bibliothèque, mais qui ne sont pas nécessaires aux utilisateurs de la bibliothèque. L'exécution du fractionnement peut être assez délicate, et de nombreuses bibliothèques ne dérangent tout simplement pas.

2
anon

Je me demandais la même chose depuis que je passe du C au C++ comme mon langage de programmation principal. Je suppose que la meilleure façon est d'utiliser des interfaces (classes abstraites en C++): vous publiez une interface publique, et votre implémentation privée utilise simplement l'interface comme classe de base.

0
Spidey