Considérez une classe comme celle-ci:
class MyReferenceClass { public: MyReferenceClass(); const double ImportantConstant1; const double ImportantConstant2; const double ImportantConstant3; private: void ComputeImportantConstants(double *out_const1, double *out_const2, double *out_const3); }
8 Réponses :
Pourquoi ne pouvez-vous pas faire: comme ça et que la fonction de calcul est de la fonction de calcul dans une fonction d'usine? p> p>
Une idée d'amélioration: faire une variable statique dans ComputeImportantConstants () et renvoyer cette variable une fois que tout est calculé. De cette façon, les appels ultérieurs de ComputeImpportantConstants ne déclenchent pas de calcul supplémentaire.
C ++ Nitpick: retourner un const double code> d'une fonction n'a pas beaucoup de sens. Cela ne rend que la vie plus difficile que nécessaire pour l'appelant sans améliorer la sécurité. Les variables de membre sont renvoyées par la valeur, après tout.
Il n'y a rien de mal avec une structure n'ayant aucune méthode et que des données de maintien (types de pod.) D'autre part, il est souvent beaucoup plus facile d'affecter les changements dans un programme si ce qui est accessible est caché derrière un appel de fonction. La plupart des gens vont préférer l'encapsulation à cause de ce dernier.
Le Nitpick est faux - il n'y a pas de const double code> renvoyé, seul un
double code> est renvoyé par une méthode
const code>, c'est-à-dire une méthode qui garantit de ne pas changer le contenu.
@Chris: Si vous regardez l'historique des changements, vous verrez qu'environ il y a environ deux ans, était i> un const double. ;-)
Tout d'abord - vous pouvez faire le mal: jeter const dans ComputeImportantConstants () et placer les valeurs là-bas. Ne le faites pas cependant, car alors vous mentez au compilateur et il tentera de trouver le moyen le plus méchant de rembourser.
second: p>
faire quelque chose comme ça: P> < Pré> xxx pré>
Vous pouvez toujours améliorer cette classe en faisant une sorte de singleton ou donc (puisque vous voulez que le calcul soit effectué une seule fois). P> P>
Vous pouvez déplacer les champs const code> à une classe de base, puis transmettez une classe d'emballage pour les initialiser:
class MyBase
{
protected:
const double ImportantConstant1;
const double ImportantConstant2;
const double ImportantConstant3;
struct Initializer
{
double d1;
double d2;
double d3;
};
MyBase(Initializer const& i):
ImportantConstant1(i.d1),ImportantConstant2(i.d2),ImportantConstant3(i.d3)
{}
};
class MyReferenceClass:
private MyBase
{
public:
using MyBase::ImportantConstant1;
using MyBase::ImportantConstant2;
using MyBase::ImportantConstant3;
MyReferenceClass():
MyBase(makeInitializer())
{}
private:
MyBase::Initializer makeInitializer()
{
MyBase::Initializer i;
ComputeImportantConstants(&i.d1,&i.d2,&i.d3);
return i;
}
void ComputeImportantConstants(double *out_const1, double *out_const2, double *out_const3);
};
Fonctionne bien; Il suffit de passer à l'héritage de la mybase publique et de rendre les deux terrains de const public public. De plus, dans le code réel, les trois valeurs sont déjà transmises dans une structure afin que je n'ai pas besoin d'une structure supplémentaire d'initialisateur. (J'aurais vraiment dû écrire ma question en utilisant cette structure ...)
Le seul moyen d'initialiser les champs de const que j'ai trouvé est d'utiliser des listes d'initialistes, mais il ne semble pas possible de passer les résultats d'un calcul multi-sorties dans une telle liste. P>
c'est vrai; Cependant, vous pouvez initialiser un seul membre - qui est une structure de constantes. Voir ci-dessous. P>
J'ai également envisagé de faire des informations importateurs1..3 des champs ou des appels de fonction non constitutifs, mais les deux semblent inférieurs. P> BlockQuote>
Je ne pense pas que les fonctions getter seraient inférieures. Le compilateur les ferait probablement les aligner. Considérez ceci: p>
xxx pré> puisque
m_constants code> ainsi que tous ses champs sont constants, les valeurs ne peuvent pas être modifiées par d'autres méthodes membres - juste dans le code vous avez esquissé dans votre question. Une initialisation peut être utilisé ici depuis que nous initialisons une seule valeur: une structure. P>
L'accès aux constantes est (très probablement) d'être aussi efficace qu'auparavant: le suggère de faire connaître les fonctions et le compilateur est assez susceptible de le faire. étant donné à quel point les getters sont petits. P> blockQuote>
Il suffit de scinder la chose dans la pièce qui est simple à initialiser et à la partie complexe et à initialiser la pièce complexe via Copier Constructeur:
// here's the part with the consts: struct ComplexPart { const double a,b,c; ComplexPart(double _a, double _b, double _c) {} }; // here's the expensive calc function: void calc(double *a,double *b,double *c); // and this is a helper which returns an initialized ComplexPart from the computation: ComplexPart calc2() { double *a,*b,*c; calc(&a,&b,&b); return ComplexPart(a,b,c); } // put everything together: struct MyReferenceClass : public ComplexPart { MyReferenceClass() : ComplexPart(calc2()) {} };
Qu'en est-il de quelque chose comme ça:
Aucune de la réponse ci-dessus semblait faire attention à un détail: En d'autres termes: Ce sont des constantes mondiales. Comme vous l'avez deviné, la présence du mot-clé Quoi qu'il en soit, l'idée est d'utiliser une structure d'assistance. P> statique code> est mentionné ici, de sorte que ces constantes semblent être indépendantes de l'instance réelle de la classe.
const code> est importante ici, en raison des optimisations du compilateur s'appliquera. P>
// foo.h
class Foo
{
public:
static double const m1;
static double const m2;
static double const m3;
};
// foo.cpp
struct Helper
{
double m1, m2, m3;
Helper() { complexInit(m1, m2, m3); }
} gHelper;
double const Foo::m1 = gHelper.m1;
double const Foo::m2 = gHelper.m2;
double const Foo::m3 = gHelper.m3;
Pour modifier la réponse acceptée, veuillez noter qu'à partir de C ++ 11, vous pouvez faire des trucs très soignés. Par exemple, votre problème d'origine peut être résolu avec une délégation de la Lambda et de la construction comme suit: ou mieux encore, déplacez le code d'initialisation de En pratique, utiliser des appels Lambda pour initialiser les membres constants est un tour très pratique, notamment parce que vous pouvez également lier et / ou passer des arguments à la Lambda. Et l'utilisation de la délégation de la construction aide à faciliter l'initialisation des membres qui peut être mieux initialisée ensemble ou pourrait dépendre de l'autre. P> Cependant, faites preuve de prudence supplémentaire lors de l'utilisation de la délégation de la construction, car l'ordre d'initialisation des arguments de fonction pour une fonction L'appel (ou un appel de constructeur) est indéfini et on pourrait finaliser d'initialiser les choses dans un ordre incorrect, ou de manière à conduire à des fuites de ressources si quelque chose échoue ou jette une exception. P> P> ComputeImportantConstants code> dans la Lambda Le constructeur, si possible. p>
Si c'est possible, pouvez-vous indiquer comment
ComputeImportantConstants code> est implémenté? Est-ce assez long? Comment les trois constantes interagissent-elles, quels autres facteurs sont impliqués?