Je travaille sur un projet C++ où j'ai un tas de fonctions mathématiques que j'ai initialement écrit pour utiliser dans le cadre d'une classe. Cependant, en écrivant plus de code, j'ai réalisé que j'avais besoin de ces fonctions mathématiques partout.
Où est le meilleur endroit pour les mettre? Disons que j'ai ceci:
class A{
public:
int math_function1(int);
...
}
Et quand j'écris une autre classe, je ne peux pas (ou du moins je ne sais pas comment) utiliser ça math_function1
dans cette autre classe. De plus, j'ai réalisé que certaines de ces fonctions ne sont pas vraiment liées à la classe A. Elles semblaient l'être au début, mais maintenant je peux voir comment ce ne sont que des fonctions mathématiques.
Quelle est la bonne pratique dans cette situation? En ce moment, je les ai copiés-collés dans les nouvelles classes, ce qui, j'en suis sûr, est la pire pratique.
C++ peut avoir des fonctions non-méthodes très bien, si elles n'appartiennent pas à une classe, ne les mettez pas dans une classe, mettez-les simplement à la portée globale ou à un autre espace de noms
namespace special_math_functions //optional
{
int math_function1(int arg)
{
//definition
}
}
Dépend de la façon dont le projet est organisé et du type de modèles de conception que vous utilisez, en supposant qu'il s'agit uniquement de code utilitaire, vous disposez des options suivantes:
Notez que la première option va être le meilleur pari et les trois suivantes sont d'une utilité limitée. Cela dit cependant, vous pourriez rencontrer alors juste à cause de C # ou Java font du travail C++ ou si vous travaillez sur C # ou Java code où l'utilisation est des cours est obligatoire.
Comme vous l'avez déjà dit, le copier-coller du code est la pire forme de réutilisation de code. Si vous avez des fonctions qui n'appartiennent à aucune de vos classes ou qui peuvent être utilisées dans plusieurs scénarios, le meilleur endroit pour les mettre serait une classe auxiliaire ou utilitaire. S'ils n'utilisent aucune donnée d'instance, ils peuvent être rendus statiques, vous n'avez donc pas besoin de créer une instance de la classe utilitaire pour l'utiliser.
Voir ici pour une discussion sur les fonctions membres statiques en C++ natif et ici pour les classes statiques en C++ managé. Vous pouvez ensuite utiliser cette classe utilitaire partout où vous auriez collé votre code.
Dans .NET par exemple, des choses comme Min()
et Max()
sont fournies en tant que membres statiques sur System.Math
classe .
Si toutes vos fonctions sont liées aux mathématiques et que vous auriez une classe Math
gigantesque, vous voudrez peut-être la décomposer davantage et avoir des classes comme TrigonometryUtilities
, EucledianGeometryUtilities
et ainsi sur.
Une autre option serait de mettre une fonctionnalité partagée dans une classe de base des classes nécessitant ladite fonctionnalité. Cela fonctionne bien, lorsque les fonctions des questions doivent fonctionner sur des données d'instance, cependant, cette approche est également moins flexible si vous voulez éviter l'héritage multiple et ne vous en tenir qu'à une seule classe de base, car vous "utiliseriez" votre base unique classe juste pour avoir accès à certaines fonctionnalités partagées.
Supprimez l'ambiguïté du terme "fonction d'assistance". Une définition est une fonction pratique que vous utilisez tout le temps juste pour faire un travail. Ceux-ci peuvent vivre dans l'espace de noms principal et avoir leurs propres en-têtes, etc. L'autre définition de fonction d'assistance est une fonction utilitaire pour une seule classe ou famille de classes.
// a general helper
template <class T>
bool isPrinter(T& p){
return (dynamic_cast<Printer>(p))? true: false;
}
// specific helper for printers
namespace printer_utils {
namespace HP {
print_alignment_page() { printAlignPage();}
}
namespace Xerox {
print_alignment_page() { Alignment_Page_Print();}
}
namespace Canon {
print_alignment_page() { AlignPage();}
}
namespace Kyocera {
print_alignment_page() { Align(137,4);}
}
namespace Panasonic {
print_alignment_page() { exec(0xFF03); }
}
} //namespace
isPrinter
est désormais disponible pour tout code, y compris son en-tête, mais print_alignment_page
Nécessite une directive using namespace printer_utils::Xerox;
. On peut aussi le référencer comme
Canon::print_alignment_page();
pour être plus clair.
Le C++ STL a l'espace de noms std::
Qui couvre presque toutes ses classes et fonctions, mais il les décompose catégoriquement en plus de 17 en-têtes différents pour permettre au codeur d'obtenir les noms de classe, les noms de fonction, etc. façon s'ils veulent écrire leur propre.
En fait, il n'est PAS recommandé d'utiliser using namespace std;
Dans un fichier d'en-tête ou, comme c'est souvent le cas, comme première ligne à l'intérieur de main()
. std::
Est composé de 5 lettres et semble souvent une corvée pour préfacer la fonction que l'on veut utiliser (en particulier std::cout
Et std::endl
!)! Mais cela sert un but.
Le nouveau C++ 11 contient des sous-espaces de noms pour des services spéciaux tels que
std::placeholders,
std::string_literals,
std::chrono,
std::this_thread,
std::regex_constants
qui peut être amené pour utilisation.
Une technique utile est composition d'espace de noms. L'un définit un espace de noms personnalisé pour contenir les espaces de noms dont vous avez besoin pour votre fichier .cpp
Particulier et l'utiliser à la place d'un tas d'instructions using
pour chaque chose dans un espace de noms dont vous pourriez avoir besoin.
#include <iostream>
#include <string>
#include <vector>
namespace Needed {
using std::vector;
using std::string;
using std::cout;
using std::endl;
}
int main(int argc, char* argv[])
{
/* using namespace std; */
// would avoid all these individual using clauses,
// but this way only these are included in the global
// namespace.
using namespace Needed; // pulls in the composition
vector<string> str_vec;
string s("Now I have the namespace(s) I need,");
string t("But not the ones I don't.");
str_vec.Push_back(s);
str_vec.Push_back(t);
cout << s << "\n" << t << endl;
// ...
Cette technique limite l'exposition à l'ensemble std:: namespace
(c'est grand!) et permet d'écrire du code plus propre pour les lignes de code les plus courantes que les gens écrivent le plus souvent.