2016-02-22 1 views
3

Supposons que je la classe suivante:déclaration avant d'un type de retour de la méthode

.h:

class MyVectorClass; 

class Foo { 
public: 
    MyVectorClass get(); 
    ... 
} 

Suivant le modèle communément accepté de transmettre déclarer tout ce qui peut être déclaré en avant, et depuis MyVectorClass est utilisé uniquement comme type de retour d'une méthode, MyVectorClass est déclaré en avant. Ensuite, tout utilisateur de cette classe doit inclure MyVectorClass.h pour pouvoir utiliser la méthode get.

Bar.cpp:

#include "Foo.h" 
#include "MyVectorClass.h" 

Foo foo; 
... 
MyVectorClass result = foo.get(); 

Le fait que pour utiliser la classe Foo nous devons inclure des en-têtes supplémentaires me fait remettre en question l'idée d'une déclaration en avant ici. C'est encore plus déroutant pour moi si j'utilise auto au lieu de MyVectorClass, ce qui est préférable car je ne me soucie pas vraiment de MyVectorClass beaucoup, tout ce qui a une interface de type vectoriel est assez bon pour moi.

#include "Foo.h" 
#include "MyVectorClass.h" 

Foo foo; 
... 
auto result = foo.get(); 

Lors de la lecture de ce code, il est très difficile de savoir pourquoi nous incluons MyVectorClass.h. Et lorsque l'interface de Foo change, et get commence à retourner AnotherVectorClass, ou std::vector, nous devrions supprimer l'ancien MyVectorClass.h dans chaque utilisateur de la méthode get et inclure un nouvel en-tête approprié à la place.

Est-ce que la déclaration directe vaut vraiment la peine ici?

+0

'auto' n'est pas une dynamique d'exécution, mais déduite lors de la compilation. Donc, pour utiliser 'result' (indépendamment de' auto'), vous devez avoir la définition complète de 'MyVectorClass' disponible. – crashmstr

+0

Si vous ne vous souciez pas du type réel, juste de son interface, pourquoi ne pas le faire de la manière STL et donner à 'foo.get' une paire d'itérateurs, ou un' insert_iterator 'qui remplira un appelant- structure fournie? – CompuChip

+0

@crashmstr Je suis conscient de ce que 'auto' est, et je ne veux pas de polymorphisme d'exécution, je veux un polymorphisme à la compilation. Le fait que j'ai besoin de la définition complète est la raison pour laquelle j'ai cette question, car le conseil général d'éviter la définition complète lorsqu'une déclaration anticipée est suffisante semble avoir un inconvénient dans cette situation. – swatmad

Répondre

1

Je pense que le problème dit que tout ce qui peut être tournées vers l'déclaré devrait être. Les déclarations anticipées offrent des avantages en termes de vitesse de compilation, mais au détriment de la commodité.

Un exemple est celui que vous avez donné. Une autre est que même les IDE et les outils (comme VisualAssist) ne savent parfois pas quoi faire d'une déclaration forward, et ne sont pas capables de passer au type réel. La même chose vaut pour les outils de refactoring.

La question de savoir si cela en vaut la peine ou non dépend de si l'amélioration de la vitesse de compilation en vaut la peine.

Si vous voulez donner un meilleur conseil aux utilisateurs de la classe, il y a une autre option: vous pouvez inclure toutes ses dépendances dans un fichier "Foo.inl", que les utilisateurs devraient inclure pour l'utiliser en toute sécurité, sans trop de tracas, et d'une manière plus à l'épreuve du futur.

0

Encore une fois, auto est typé statiquement et ne vous aidera pas à obtenir le polymorphisme dynamique souhaité. Si vous en avez besoin, vous devriez utiliser des itérateurs ou des pointeurs. Par conséquent, une solution consistera à hériter de toutes vos classes d'implémentation SomeVector de la même classe de base. Vous n'aurez donc pas besoin de modifier les inclusions chaque fois que vous modifiez quelque chose.

Vous pouvez travailler avec les données get() vous donne d'abord la main, à condition MyVectorClass a itérateurs propres, et ne jamais utiliser du tout le type SomeVector intermédiaire. C'est mieux pour votre cas, car vous pouvez également utiliser le vecteur stl lui-même.