Quelle est la signification de const
dans de telles déclarations? Le const
me confond.
class foobar
{
public:
operator int () const;
const char* foo() const;
};
Quelle est la signification de const
dans de telles déclarations? Le const
me confond.
class foobar
{
public:
operator int () const;
const char* foo() const;
};
Réponses:
Lorsque vous ajoutez le const
mot - clé à une méthode, le this
pointeur devient essentiellement un pointeur vers un const
objet et vous ne pouvez donc pas modifier les données de membre. (Sauf si vous utilisez mutable
, plus à ce sujet plus tard).
Le const
mot-clé fait partie de la signature des fonctions, ce qui signifie que vous pouvez implémenter deux méthodes similaires, une qui est appelée lorsque l'objet l'est const
et une qui ne l'est pas.
#include <iostream>
class MyClass
{
private:
int counter;
public:
void Foo()
{
std::cout << "Foo" << std::endl;
}
void Foo() const
{
std::cout << "Foo const" << std::endl;
}
};
int main()
{
MyClass cc;
const MyClass& ccc = cc;
cc.Foo();
ccc.Foo();
}
Cela produira
Foo
Foo const
Dans la méthode non const, vous pouvez modifier les membres de l'instance, ce que vous ne pouvez pas faire dans la const
version. Si vous changez la déclaration de méthode dans l'exemple ci-dessus par le code ci-dessous, vous obtiendrez des erreurs.
void Foo()
{
counter++; //this works
std::cout << "Foo" << std::endl;
}
void Foo() const
{
counter++; //this will not compile
std::cout << "Foo const" << std::endl;
}
Ce n'est pas tout à fait vrai, car vous pouvez marquer un membre comme mutable
et une const
méthode peut ensuite le modifier. Il est principalement utilisé pour les compteurs internes et autres. La solution pour cela serait le code ci-dessous.
#include <iostream>
class MyClass
{
private:
mutable int counter;
public:
MyClass() : counter(0) {}
void Foo()
{
counter++;
std::cout << "Foo" << std::endl;
}
void Foo() const
{
counter++; // This works because counter is `mutable`
std::cout << "Foo const" << std::endl;
}
int GetInvocations() const
{
return counter;
}
};
int main(void)
{
MyClass cc;
const MyClass& ccc = cc;
cc.Foo();
ccc.Foo();
std::cout << "Foo has been invoked " << ccc.GetInvocations() << " times" << std::endl;
}
qui produirait
Foo
Foo const
Foo has been invoked 2 times
Le const signifie que la méthode promet de ne modifier aucun membre de la classe. Vous seriez en mesure d'exécuter les membres de l'objet qui sont ainsi marqués, même si l'objet lui-même était marqué const
:
const foobar fb;
fb.foo();
serait légal.
Voir Combien et quelles sont les utilisations de «const» en C ++? pour plus d'informations.
Le const
qualificatif signifie que les méthodes peuvent être appelées sur n'importe quelle valeur de foobar
. La différence survient lorsque vous envisagez d'appeler une méthode non const sur un objet const. Vérifiez si votre foobar
type a la déclaration de méthode supplémentaire suivante:
class foobar {
...
const char* bar();
}
La méthode bar()
est non const et n'est accessible qu'à partir de valeurs non const.
void func1(const foobar& fb1, foobar& fb2) {
const char* v1 = fb1.bar(); // won't compile
const char* v2 = fb2.bar(); // works
}
L'idée derrière const
est cependant de marquer des méthodes qui ne modifieront pas l'état interne de la classe. Il s'agit d'un concept puissant mais qui n'est pas réellement applicable en C ++. C'est plus une promesse qu'une garantie. Et celui qui est souvent cassé et facilement cassé.
foobar& fbNonConst = const_cast<foobar&>(fb1);
const
est de marquer des méthodes qui ne modifieront pas l'état interne de la classe". C'est vraiment ce que je cherchais.
const
?
Ces const signifient que le compilateur générera une erreur si la méthode «avec const» modifie les données internes.
class A
{
public:
A():member_()
{
}
int hashGetter() const
{
state_ = 1;
return member_;
}
int goodGetter() const
{
return member_;
}
int getter() const
{
//member_ = 2; // error
return member_;
}
int badGetter()
{
return member_;
}
private:
mutable int state_;
int member_;
};
Le test
int main()
{
const A a1;
a1.badGetter(); // doesn't work
a1.goodGetter(); // works
a1.hashGetter(); // works
A a2;
a2.badGetter(); // works
a2.goodGetter(); // works
a2.hashGetter(); // works
}
Lisez ceci pour plus d'informations
const
les fonctions membres qui ne mentionne pas mutable est au mieux incomplète.
La réponse de Blair est dans le mille.
Notez toutefois qu'il existe un mutable
qualificatif qui peut être ajouté aux membres de données d'une classe. Tout membre ainsi marqué peut être modifié dans une const
méthode sans violer le const
contrat.
Vous pouvez utiliser ceci (par exemple) si vous voulez qu'un objet se souvienne combien de fois une méthode particulière est appelée, sans affecter la constance "logique" de cette méthode.
Signification d'une fonction membre Const en C ++ Connaissance courante: la programmation intermédiaire essentielle donne une explication claire:
Le type du pointeur this dans une fonction membre non const d'une classe X est X * const. Autrement dit, c'est un pointeur constant vers un X non constant (voir Const Pointers et Pointers to Const [7, 21]). Étant donné que l'objet auquel cela se réfère n'est pas const, il peut être modifié. Le type de ceci dans une fonction membre const d'une classe X est const X * const. C'est-à-dire que c'est un pointeur constant vers un X constant. Parce que l'objet auquel cela se réfère est const, il ne peut pas être modifié. C'est la différence entre les fonctions membres const et non const.
Donc dans votre code:
class foobar
{
public:
operator int () const;
const char* foo() const;
};
Vous pouvez le penser comme ceci:
class foobar
{
public:
operator int (const foobar * const this) const;
const char* foo(const foobar * const this) const;
};
this
ne l'est pas const
. La raison pour laquelle il ne peut pas être modifié est qu'il s'agit d'une valeur.
lorsque vous utilisez const
dans la signature de méthode (comme votre dit:) vous dites const char* foo() const;
au compilateur que la mémoire pointée par this
ne peut pas être modifiée par cette méthode (qui est foo
ici).
Je voudrais ajouter le point suivant.
Vous pouvez également en faire un const &
etconst &&
Donc,
struct s{
void val1() const {
// *this is const here. Hence this function cannot modify any member of *this
}
void val2() const & {
// *this is const& here
}
void val3() const && {
// The object calling this function should be const rvalue only.
}
void val4() && {
// The object calling this function should be rvalue reference only.
}
};
int main(){
s a;
a.val1(); //okay
a.val2(); //okay
// a.val3() not okay, a is not rvalue will be okay if called like
std::move(a).val3(); // okay, move makes it a rvalue
}
N'hésitez pas à améliorer la réponse. Je ne suis pas un expert
*this
est toujours une valeur l, même si la fonction membre est qualifiée rvalue-ref et est appelée sur une valeur r. Exemple .
Le mot clé const utilisé avec la déclaration de fonction spécifie qu'il s'agit d'une fonction membre const et qu'il ne pourra pas modifier les membres de données de l'objet.
https://isocpp.org/wiki/faq/const-correctness#const-member-fns
Qu'est-ce qu'une "
const
fonction membre"?Une fonction membre qui inspecte (plutôt que mute) son objet.
Une
const
fonction membre est indiquée par unconst
suffixe juste après la liste des paramètres de la fonction membre. Les fonctions membres avec unconst
suffixe sont appelées «fonctions membres const» ou «inspecteurs». Les fonctions membres sansconst
suffixe sont appelées «fonctions membres non const» ou «mutateurs».class Fred { public: void inspect() const; // This member promises NOT to change *this void mutate(); // This member function might change *this }; void userCode(Fred& changeable, const Fred& unchangeable) { changeable.inspect(); // Okay: doesn't change a changeable object changeable.mutate(); // Okay: changes a changeable object unchangeable.inspect(); // Okay: doesn't change an unchangeable object unchangeable.mutate(); // ERROR: attempt to change unchangeable object }
La tentative d'appel
unchangeable.mutate()
est une erreur interceptée lors de la compilation. Il n'y a pas d'espace d'exécution ni de pénalité de vitesse pourconst
, et vous n'avez pas besoin d'écrire des cas de test pour le vérifier lors de l'exécution.La fonction de fin
const
deinspect()
membre doit être utilisée pour signifier que la méthode ne changera pas l'état abstrait (visible par le client) de l'objet. C'est légèrement différent de dire que la méthode ne changera pas les «bits bruts» de la structure de l'objet. Les compilateurs C ++ ne sont pas autorisés à prendre l'interprétation «au niveau du bit» à moins qu'ils ne puissent résoudre le problème d'alias, qui ne peut normalement pas être résolu (c'est-à-dire qu'un alias non-const pourrait exister qui pourrait modifier l'état de l'objet). Un autre aperçu (important) de ce problème d'alias: pointer sur un objet avec un pointeur vers const ne garantit pas que l'objet ne changera pas; il promet simplement que l'objet ne changera pas via ce pointeur .