web-dev-qa-db-fra.com

Façons d'organiser l'interface et la mise en œuvre en C ++

J'ai vu qu'il existe plusieurs paradigmes différents en C++ concernant ce qui se passe dans le fichier d'en-tête et sur quoi le fichier CPP. Afaik, la plupart des gens, en particulier ceux d'une base C, font:

foo.h

 class foo {
 private:
     int mem;
     int bar();
 public:
     foo();
     foo(const foo&);
     foo& operator=(foo);
     ~foo();
 }

foo.cpp

 #include foo.h
 foo::bar() { return mem; }
 foo::foo() { mem = 42; }
 foo::foo(const foo& f) { mem = f.mem; }
 foo::operator=(foo f) { mem = f.mem; }
 foo::~foo() {}
 int main(int argc, char *argv[]) { foo f; }

Cependant, mes conférenciers enseignent généralement C++ aux débutants comme ceci:

foo.h

 class foo {
 private:
     int mem;
     int bar() { return mem; }
 public:
     foo() { mem = 42; }
     foo(const foo& f) { mem = f.mem; }
     foo& operator=(foo f) { mem = f.mem; }
     ~foo() {}
 }

foo.cpp

 #include foo.h
 int main(int argc, char* argv[]) { foo f; }
 // other global helper functions, DLL exports, and whatnot

À l'origine venant de Java, j'ai également toujours collé à cette seconde façon pour plusieurs raisons, telles que je dois seulement changer quelque chose au même endroit si l'interface ou les noms de méthode changent, que j'aime la différence d'indentation des choses dans les classes quand je Regardez leur mise en œuvre et que je trouve des noms plus lisibles comme foo par rapport à foo::foo.

Je veux collecter des professionnels et des con gens de l'une ou de l'autre manière. Peut-être qu'il y a même encore d'autres manières?

Un inconvénient de mon chemin est bien sûr la nécessité de déclarations avancées occasionnelles.

12
Felix Dombek

Bien que la deuxième version soit plus facile à écrire, elle mélange une interface avec la mise en œuvre.

Les fichiers source incluent des fichiers d'en-tête doivent être recompantés à chaque fois que les fichiers d'en-tête sont modifiés. Dans la première version, vous ne modifiez que le fichier d'en-tête uniquement si vous devez modifier l'interface. Dans la deuxième version, vous modifiez le fichier d'en-tête si vous devez modifier l'interface ou la mise en œuvre.

En plus de cela, vous devriez ne pas exposer les détails de la mise en œuvre, vous obtiendrez recompilation inutile avec la deuxième version.

16
LennyProgrammers

Je l'ai fait la deuxième façon de retourner '93 -95. A pris quelques minutes pour recompiler une petite application avec 5-10 fonctions/fichiers (sur la même pièce 486 pc .. Et non, je ne connaissais pas les cours non plus, j'avais seulement 14-15 ans et Il n'y avait pas d'internet ).

Ainsi, ce que vous enseignez les débutants et ce que vous utilisez professionnellement est des techniques très différentes, en particulier en C++.

Je pense que la comparaison entre C++ et une voiture F1 est apte. Vous ne mettez pas les débutants dans une voiture F1 (qui ne démarre même pas à moins que vous ne chauffiez pas le moteur à 80-95 degrés Celcius).

N'enseigne pas C++ comme première langue. Vous devriez être suffisamment expérimenté pour savoir pourquoi l'option 2 est pire que l'option 1 en général, sachez un peu ce que signifie la compilation/liaison statique et comprend ainsi pourquoi C++ préfère la première façon.

3
Macke

La deuxième méthode est ce que j'appellerais une classe totalement inline. Vous écrivez une définition de classe mais tout votre code à l'aide de celui-ci ne fera que souscrire le code.

Oui, le compilateur décide quand en ligne et quand ne pas ... Dans ce cas, vous aidez le compilateur à prendre une décision, et vous finirez potentiellement à générer moins de code et potentiellement plus rapide.

Cet avantage est susceptible d'emporter le fait que si vous modifiez la mise en œuvre d'une fonction, vous devez reconstruire toute la source qui l'utilise. Dans la nature légère de la classe, vous ne modifiez pas la mise en œuvre. Si vous ajoutez une nouvelle méthode, vous devez modifier l'en-tête de toute façon.

Comme votre classe devient toutefois plus complexe, en ajoutant même une boucle, l'avantage de le faire de cette façon diminue.

Il a encore ses avantages, en particulier:

  • S'il s'agit d'un code "Common-fonctionnalité", vous pouvez simplement inclure l'en-tête et l'utiliser à partir de plusieurs projets sans avoir à créer un lien avec une bibliothèque contenant sa source.

L'inconvénient de l'inlinisation devient un problème quand cela signifie que vous devez apporter des spécificités de mise en œuvre dans votre en-tête, c'est-à-dire que vous devez commencer, y compris les en-têtes supplémentaires.

Notez que les modèles sont un cas particulier car vous devez inclure à peu près les détails de la mise en œuvre. Vous pouvez l'obscurcir dans un autre fichier, mais il doit être là. (Il y a une exception à cette règle avec les instanciations, mais en général, vous en ligne vos modèles).

2
CashCow

Il peut ne pas être significatif, ou vrai si votre exécutable devient plus grande, mais plus de code dans les fichiers d'en-tête permet au compilateur de plus de chances d'optimiser la vitesse.

Si vous êtes décider s'il faut écrire une bibliothèque d'en-tête uniquement , ce sujet n'est qu'une de vos préoccupations.

1
davidvandebunte