Pimpl idiome vs classe virtuelle Pure interface
Je me demandais ce qui ferait un programmeur de choisir soit Pimpl idiome ou classe virtuelle pure et à l'héritage.
Je comprends que pimpl idiome est livré avec un explicite supplémentaire d'indirection pour chaque méthode publique et la création de l'objet de frais généraux.
La classe virtuelle Pure dans l'autre main est livré avec implicite d'indirection(vtable) pour hériter de la mise en œuvre et je comprends que je ne la création d'un objet de frais généraux.
MODIFIER: Mais vous auriez besoin d'une usine si vous créez l'objet de l'extérieur
Ce qui rend la classe virtuelle pure moins désirable que le pimpl idiome?
- Bonne question, je voulais juste demander la même chose. Voir aussi boost.org/doc/libs/1_41_0/libs/smart_ptr/sp_techniques.html
Vous devez vous connecter pour publier un commentaire.
Lors de l'écriture d'une classe C++, il est correct de penser si cela va être
Une Valeur De Type
Copie par valeur, l'identité n'est jamais important. Il est utile qu'il soit d'une clé dans une std::map. Exemple, une "chaîne" de la classe, ou d'une "date" de la classe, ou un "nombre complexe" de la classe. De "copier" les instances de la classe a du sens.
Un type d'Entité
Identité est importante. Toujours passés par référence, jamais par "valeur". Souvent, ne fait pas de sens à "copier" les instances de la classe à tous. Quand il ne fait sens, un polymorphe "Clone" de la méthode est généralement plus approprié. Exemples: Une classe Socket, une Base de données de la classe, une "politique" de classe, tout ce qui pourrait être une "fermeture" dans un langage fonctionnel.
Les deux pImpl et de la classe de base abstraite pure sont des techniques pour réduire le temps de compilation des dépendances.
Cependant, je n'ai jamais utiliser pImpl à mettre en œuvre des types de Valeur (de type 1), et que parfois quand j'ai vraiment envie de minimiser le couplage et la compilation des dépendances. Souvent, il n'en vaut pas la peine. Comme vous le faites justement remarquer, il n'y a plus d'syntaxique généraux parce que vous avez à écrire transfert des méthodes pour toutes les méthodes publiques. Pour le type 2 classes, j'ai toujours utiliser une classe de base abstraite pure associée à l'usine de méthode(s).
Pointer to implementation
est habituellement d'environ cacher structurels détails de mise en œuvre.Interfaces
sont sur l'instanciation des implémentations différentes. Ils ont vraiment servir à deux fins.Le pimpl idiome vous permet de réduire les dépendances de construction et de temps, particulièrement dans les grandes applications, et minimise l'en-tête de l'exposition des détails de mise en œuvre de votre classe à une unité de compilation. Les utilisateurs de votre classe ne devrait même pas besoin d'être conscient de l'existence d'un bouton (sauf une énigme de pointeur à laquelle ils ne sont pas au courant!).
Les classes abstraites (pur virtuals) est quelque chose dont vos clients doivent être conscients: si vous essayez de les utiliser pour réduire le couplage et les références circulaires, vous devez ajouter un peu de façon de leur permettre de créer vos objets (par exemple, par le biais de méthodes de fabrique ou de cours de l'injection de dépendance ou d'autres mécanismes).
J'étais à la recherche d'une réponse à la même question.
Après la lecture de certains articles et de certaines pratiques , je préfère utiliser "classe virtuelle Pure interfaces".
Mais si vous voulez bénéficier du polymorphisme: c'est aussi "pro", pas un "con". ...et une simple méthode de fabrique n'a pas vraiment fait mal tellement
Le seul inconvénient (je suis en train d'enquêter sur cette), c'est que pimpl idiome pourrait être plus rapide
Je déteste les boutons! Ils ne le classe laid et pas lisible. Toutes les méthodes sont redirigés vers le bouton. Vous ne verrez jamais dans les en-têtes, ce qui fonctionnalites a de la classe, de sorte que vous ne pouvez pas refactoriser (e. g. simplement changer la visibilité d'une méthode). La classe se sent comme "enceinte". Je pense que l'utilisation iterfaces est mieux et vraiment assez pour cacher la mise en œuvre de la part du client. Vous pouvez laisser une classe d'implémenter plusieurs interfaces pour les tenir mince. On doit préférer les interfaces!
Remarque: Vous n'avez pas besoin de l'usine de la classe. Pertinent, c'est que la classe clients de communiquer avec les instances via l'interface appropriée.
Le masquage des méthodes privées, je trouve étrange de la paranoïa et de ne pas voir de raison pour cela, car nous vha interfaces.
Il y a un réel problème avec les bibliothèques partagées qui le pimpl idiome contourne soigneusement que pure virtuals ne peut pas: vous ne pouvez pas sûre de modifier/supprimer les données membres d'une classe sans obliger les utilisateurs de la classe de recompiler le code. Qui peut être acceptable dans certaines circonstances, mais pas par exemple pour les bibliothèques système.
Pour expliquer le problème en détail, considérons le code suivant dans votre bibliothèque partagée/en-tête:
Le compilateur émet le code dans la bibliothèque partagée qui calcule l'adresse de l'entier à être initialisée à être un certain décalage (probablement à zéro dans ce cas, car il est le seul membre) à partir du pointeur à Un objet qu'il connaît pour être
this
.Du côté de l'utilisateur du code, un
new A
va allouersizeof(A)
octets de mémoire, puis à la main un pointeur vers la mémoire de laA::A()
constructeur commethis
.Si dans une révision ultérieure de votre bibliothèque, vous décidez d'abandonner l'entier, de le rendre plus grand, plus petit, ou ajouter des membres, il y a un décalage entre la quantité de mémoire de l'utilisateur du code alloue, et les décalages le code du constructeur attend. Le résultat probable est un accident, si vous avez de la chance - si vous êtes moins chanceux, votre logiciel se comporte bizarrement.
Par pimpl require, vous pouvez ajouter et supprimer des membres de données à l'intérieur de la classe, comme l'allocation de la mémoire et de l'appel du constructeur arriver dans la bibliothèque partagée:
Tout ce que vous devez faire maintenant est de garder votre interface publique libre de membres de données autres que le pointeur de la mise en œuvre de l'objet, et vous êtes sûr de cette classe d'erreurs.
Edit: je devrais peut-être ajouter que la seule raison pour laquelle je parle du constructeur ici, c'est que je ne veux pas donner de code plus la même argumentation s'applique à toutes les fonctions d'accès aux données membres.
class A_impl *impl_;
Nous ne devons pas oublier que l'héritage est plus fort, plus près de couplage de la délégation. Je voudrais également prendre en compte toutes les questions soulevées dans les réponses données au moment de décider quels sont les idiomes d'employer à résoudre un problème particulier.
Bien que largement couverte par les autres réponses peut-être que je peux être un peu plus explicite au sujet de l'avantage de pimpl plus virtuel classes de base:
Un pimpl approche est transparent du point de vue de l'utilisateur, ce qui signifie que vous pouvez par exemple créer des objets de la classe sur la pile et de les utiliser directement dans des conteneurs. Si vous essayez de masquer la mise en œuvre à l'aide d'un résumé virtuel de la classe de base, vous aurez besoin de retourner un pointeur partagé de la classe de base de l'usine, ce qui complique son utilisation. Considérons le schéma équivalent suivant le code de client:
Le plus ennuyeux problème sur le pimpl idiome est-il fait qu'il est extrêmement difficile à maintenir et à analyser le code existant. Donc, en utilisant pimpl vous payez avec le développeur de temps et de frustration seulement de les "réduire les dépendances de construction et de temps et de minimiser l'en-tête de l'exposition des détails de mise en œuvre". Décidez vous-même, si c'est vraiment la peine.
Surtout "les temps de construire" est un problème que vous pouvez résoudre par une meilleure gestion du matériel ou à l'aide d'outils comme Incredibuild ( http://www.incredibuild.com, également déjà inclus dans Visual Studio 2017 ), donc pas affecter votre logiciel de conception. Logiciel de conception devrait être généralement indépendante de la façon dont le logiciel est construit.
Dans ma compréhension de ces deux choses servent objectifs complètement différents. Le but de la pimple idiome est essentiellement de vous donner une poignée pour votre application de sorte que vous pouvez faire des choses comme rapide des swaps pour un tri.
Le but de classes virtuelles est plus le long de la ligne de permettre le polymorphisme, c'est à dire que vous avez un inconnu pointeur vers un objet de type dérivé et lorsque vous appelez la fonction x-vous de toujours avoir la bonne fonction pour quelle que soit la classe le pointeur de la base en fait des points d'.
Les pommes et les oranges vraiment.