2016-03-15 1 views
0

Lors de la création d'une classe composée d'autres classes, est-il utile de réduire les dépendances (et donc de compiler les temps) en utilisant des pointeurs plutôt que des valeurs?Les pointeurs doivent-ils être utilisés pour réduire les dépendances d'en-tête?

Par exemple, la valeur ci-dessous utilise des valeurs.

// ThingId.hpp 
class ThingId 
{ 
    // ... 
}; 

// Thing.hpp 
#include "ThingId.hpp" 
class Thing 
{ 
public: 
    Thing(const ThingId& thingId); 
private: 
    ThingId thingId_; 
}; 

// Thing.cpp 
#include "Thing.hpp" 
Thing::Thing(const ThingId& thingId) : 
    thingId_(thingId) {} 

Cependant, la version modifiée ci-dessous utilise des pointeurs.

// ThingId.hpp 
class ThingId 
{ 
    // ... 
}; 

// Thing.hpp 
class ThingId; 
class Thing 
{ 
public: 
    Thing(const ThingId& thingId); 
private: 
    ThingId* thingId_; 
}; 

// Thing.cpp 
#include "ThingId.hpp" 
#include "Thing.hpp" 
Thing::Thing(const ThingId& thingId) : 
    thingId_(new ThingId(thingId)) {} 

J'ai lu un message qui recommande une telle approche, mais si vous avez un grand nombre de pointeurs, il y aura un grand nombre de new appels, ce qui je crois serait lente.

+0

"vaut-il la peine de réduire les dépendances (et donc de compiler les temps) en utilisant des pointeurs plutôt que des valeurs?" - Je ne vois pas comment utiliser les pointeurs "réduit les dépendances" - ni comment cela a une relation avec le temps de compilation. – Dai

+0

Il n'y a rien à propos d'un pointeur qui nécessite un appel 'new'. Je peux écrire un tas de code, avec des pointeurs partout, et pas un seul appel 'new'. –

+0

@Dai: Vous pouvez retransmettre le type de pointee plutôt que "#include" l'en-tête complet dans lequel le type est entièrement défini. –

Répondre

2

Si votre programme ne justifie pas une allocation dynamique, ne le présentez pas uniquement pour l'organisation d'un projet. Ce serait certainement une fausse économie.

Ce que vous voulez vraiment faire est de tenter de réduire entièrement le nombre de dépendances entre classes.

Cependant, tant que votre couplage est sensible et arborescente, ne vous en faites pas trop. Si vous utilisez des en-têtes précompilés (et vous l'êtes, non?), Rien de tout cela ne compte vraiment pour les temps de compilation.

+0

Je pense que le problème est aussi de grands arbres de dépendance. De petites modifications, éventuellement non pertinentes, dans certains en-têtes peuvent entraîner la recompilation du projet. Pour les grands projets qui peuvent être prohibitifs, par exemple, éviter les builds nocturnes et les tests. C'était une question quand j'ai postulé pour un emploi à Star Division (Star Office, plus tard OpenOffice) à Hambourg: "Si vous voulez ajouter une fonction virtuelle à une classe polymorphe sans recompiler tous les fichiers qui utilisent cette classe, où placez-vous nouvelle fonction dans la déclaration de classe? " (À la fin, parce que tous les décalages antérieurs dans la VTable ne changent pas.) –

+0

"Ce que vous voulez vraiment faire est de tenter de réduire le nombre de dépendances inter-classe entièrement." Des références sur les approches pour le faire? – magnus

+0

@ user1420752: Tout bon livre sur la conception de logiciels, vraiment –

3

C'est ce que la plupart des gens appellent l'idiome de Pimpl (http://c2.com/cgi/wiki?PimplIdiom).

simple réponse

Je soupçonne fortement que vous ne disposez pas d'un bon cas d'utilisation pour cela et doit éviter à tout prix.

Mon expérience

La principale façon que Pimpl n'a jamais été utile pour moi est de faire un détail de mise en œuvre privée. Il y parvient car vous n'avez pas besoin d'inclure les en-têtes de vos dépendances, mais vous pouvez simplement transmettre les types déclarés.

Exemple

Si vous voulez fournir un SDK à quelqu'un qui utilise un code de la bibliothèque Boost sous le capot, mais vous voulez avoir la possibilité d'échanger plus tard que pour une autre bibliothèque sans causer aucun problème pour le consommateur de votre SDK, alors Pimpl peut avoir beaucoup de sens. Il permet également de créer une façade sur une implémentation, de sorte que contrôle l'ensemble de l'interface publique exposée, plutôt que d'exposer la bibliothèque dont vous dépendez implicitement, et par conséquent toute son interface sur laquelle vous n'avez aucun contrôle. et peut changer, peut exposer trop, peut être difficile à utiliser, etc.

+0

Je ne vois aucune preuve de Pimpl ici. –