C++ définition d'une constante variable membre à l'intérieur de constructeur de classe
Habituellement, lorsque vous avez une constante variable membre privée dans votre classe, qui n'a qu'un getter, mais pas de setter, il ressemblerait à quelque chose comme ceci:
//Example.h
class Example {
public:
Example(const int value);
const int getValue() const;
private:
const int m_value;
};
//Example.cpp
#include "Example.h"
Example::Example(const int value)
: m_value(value)
{
}
const int Example::getValue() const
{
return m_value;
}
Maintenant ce que j'essaie de faire, c'est avoir une constante de type int variable membre comme ça, mais au lieu de le définir dans l'initialisation de l'article comme suit: : m_value(value)
j'ai besoin de prendre un autre objet - je vais utiliser un vecteur dans cet exemple - comme le constructeur du paramètre, et l'ensemble de m_value basé sur le paramètre de l'objet. Dans ce cas, je vais essayer de faire du vecteur de taille de + 1, si la taille est au-dessus de 0. C'est donc ce que j'ai fait:
Example::Example(std::vector<Example*> myVec)
{
if (myVec.size()) {
m_value = myVec.size() + 1;
}
else {
m_value = -1;
}
}
Mais j'obtiens une erreur uninitialized member 'Example::m_value' with 'const' type 'const int'
et si je init m_value à l'intérieur de l'initialisation de l'article, j'obtiens l'erreur assignment of read-only data-member 'Example::m_value'
qui prend tout son sens pour moi, je suis censé obtenir ces erreurs, mais comment pourrais-je aller autour d'eux?
Edit: Seule façon que je pouvais modifier m_value
est à l'intérieur de l'objet lui-même (depuis m_value est privé). Le fait d'avoir seulement getter limiterait moi de réglage de m_value à autre chose que ce qu'il est défini dans le constructeur. Puis-je bénéficier de tout, d'avoir de la constante de type int comme une variable de membre?
: m_value(!myVec.empty() ? myVec.size() + 1 : -1)
?pourquoi a-t-elle à être
const
?Par rapport à votre mise à jour - non, aucun des avantages que je peux voir...
C'est constant, de sorte qu'il ne peut jamais être changé de toute façon. Je suis en l'utilisant comme identifiant unique pour les objets dans mon jeu, et je veux que ces identificateurs de rester le même pendant tout le match. Je pensais que ça serait une bonne idée pour la rendre constante, toujours pas sûr de savoir les avantages.
Vous obtenez une certaine valeur. Le compilateur peut faire l'hypothèse que, quoi qu'il arrive, les appels répétés à la lecture pour le même objet donnera la même valeur. Mais en l'utilisant comme un identifiant unique, et bien... c'est ce que les pointeurs sont pour.
OriginalL'auteur | 2012-11-27
Vous devez vous connecter pour publier un commentaire.
Utiliser une fonction membre statique de calcul de résultat dont vous avez besoin et appeler cette fonction dans la liste d'initialisation. Comme ceci:
Dans ce cas particulier, la fonction est donc très simple, il suffit d'utiliser l'opérateur ternaire (aka
: m_value(myVec.size() > 0 ? int(myVec.size() + 1) : int(-1)
) dans le constructeur de calculer directement la valeur au moment de l'initialisation. Cela ressemblait à un exemple, si je vous ai donné un très méthode générale de résolution de problème, même lorsque la méthode de calcul de la réponse dont vous avez besoin peut être très complexe.Le problème général est que les constantes des variables membres (et membre des variables qui sont des références trop BTW) doit être initialisé dans la liste d'initialiseur. Mais les initialiseurs peuvent être des expressions, ce qui signifie qu'ils peuvent appeler des fonctions. Depuis ce code d'initialisation est assez spécifique à la classe, il devrait être une fonction privée (ou peut-être protégé) à la classe. Mais, puisqu'il est appelé à créer une valeur avant de la classe est construite, il ne peuvent pas s'appuyer sur une instance de classe d'exister, donc pas de
this
pointeur. Cela signifie qu'il doit être une fonction membre statique.Maintenant, le type de
myVec.size()
eststd::vector<Example*>::size_t
, et que ce type est non signé. Et vous êtes à l'aide d'une sentinelle de la valeur de -1, ce qui ne l'est pas. Et vous êtes les stockant dans unint
qui peut ne pas être la bonne taille pour tenir de toute façon. Si votre vecteur est petit, ce n'est probablement pas un problème. Mais si votre vecteur acquiert une taille en fonction de l'entrée externe, ou si vous ne savez pas comment grand il va devenir, ou n'importe quel nombre d'autres facteurs, cela va devenir un problème. Vous devez penser à qui et à adapter votre code en conséquence.OriginalL'auteur Omnifarious
Tout d'abord, la variable est défini dans la définition de classe, pas dans le constructeur. C'est initialisé dans le constructeur.
Deuxième, la façon de le faire est juste comme ce que votre constructeur ne le fait actuellement: stocker la valeur à partir de la liste d'initialiseur:
voir la réponse donnée par Omnifarious.
Puis vous écrire une petite fonction helper qui fait
OriginalL'auteur Pete Becker
Vous avez deux options de base. La première consiste à utiliser l'opérateur conditionnel, ce qui est bien pour des conditions simples comme la vôtre:
Pour des choses plus complexes, vous pouvez déléguer le calcul d'une fonction membre. Soyez prudent de ne pas appeler de membre virtuel fonctions à l'intérieur d'elle, comme il sera appelé lors de la construction. Il est plus sûr de le faire
static
:Ce dernier travaille avec des définitions de classe, bien sûr. Je les ai placés dans la classe pour économiser de l'espace & taper.
OriginalL'auteur Angew
Cette réponse traite d'un problème avec toutes les autres réponses:
Cette suggestion est mauvais:
L'opérateur conditionnel apporte son deuxième et troisième opérande de type commun, indépendamment de la sélection finale.
Dans ce cas, le type le plus commun de
size_t
etint
estsize_t
. Donc, si le vecteur est vide, la valeur(size_t)-1
est affecté à laint
m_value, qui est un en dehors de la plage de conversion, en invoquant la mise en œuvre définies par le comportement.Afin d'éviter le recours à la mise en oeuvre comportement défini le code pourrait être:
Maintenant, il conserve un autre problème que le code d'origine: en dehors de la plage de conversion lorsque
myVec.size() >= INT_MAX
. Dans un solide code de ce problème doit également être abordé.Je préfère personnellement la suggestion d'ajouter une fonction d'assistance, qui effectue ce test d'autonomie et lève une exception si la valeur est hors de portée. Le one-liner est possible, bien que le code commence à devenir difficile à lire:
Bien sûr, il existe d'autres façons de traiter ce problème de façon plus propre, par exemple l'utilisation
size_t
pourm_value
et soit(size_t)-1
comme la sentinelle de la valeur, ou, de préférence, éviter le besoin d'une sentinelle de la valeur entièrement.OriginalL'auteur M.M