web-dev-qa-db-fra.com

Signification de 'const' last dans une déclaration de fonction d'une classe?

Quel est le sens de const dans des déclarations comme celles-ci? La const me déroute.

class foobar
{
  public:
     operator int () const;
     const char* foo() const;
};
666
user91111

Lorsque vous ajoutez le mot clé const à une méthode, le pointeur this devient essentiellement un pointeur sur l'objet const. Par conséquent, vous ne pouvez modifier aucune donnée de membre. (Sauf si vous utilisez mutable, vous en saurez plus à ce sujet plus tard).

Le mot clé const fait partie de la signature de la fonction, ce qui signifie que vous pouvez implémenter deux méthodes similaires, l'une appelée lorsque l'objet est const et l'autre non.

#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 version const. Si vous modifiez la déclaration de méthode dans l'exemple ci-dessus pour 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 étant mutable et une méthode const peut alors le changer. Il est principalement utilisé pour les compteurs internes. 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++;
        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 << "The MyClass instance has been invoked " << ccc.GetInvocations() << " times" << endl;
}

qui produirait

Foo
Foo const
The MyClass instance has been invoked 2 times
874
Mats Fredriksson

La constante signifie que la méthode promet de ne modifier aucun membre de la classe. Vous seriez capable 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.

175
Blair Conrad

Le qualificateur const signifie que les méthodes peuvent être appelées sur n'importe quelle valeur de foobar. La différence vient lorsque vous envisagez d'appeler une méthode non-const sur un objet const. Déterminez si votre type foobar avait la déclaration de méthode supplémentaire suivante:

class foobar {
  ...
  const char* bar();
}

La méthode bar() est non-constante et est accessible uniquement à 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. C'est un concept puissant, mais qui n'est pas réellement applicable en C++. C'est plus une promesse qu'une garantie. Et un qui est souvent cassé et facilement cassé.

foobar& fbNonConst = const_cast<foobar&>(fb1);
43
JaredPar

Ces const signifient que le compilateur Error si la méthode 'with 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
}

Lire this pour plus d'informations

22
Mykola Golubyev

La réponse de Blair est sur la marque.

Cependant, notez qu'il existe un qualificatif mutable qui peut être ajouté aux membres de données d'une classe. Tout membre ainsi marqué can peut être modifié dans une méthode const sans violer le contrat const.

Vous voudrez peut-être utiliser ceci (par exemple) si vous voulez qu'un objet se souvienne du nombre de fois qu'une méthode particulière est appelée, sans affecter la constness "logique" de cette méthode.

11
Alnitak

Signification d'une fonction membre Const dans Connaissance commune C++: 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. C’est-à-dire qu’il s’agit d’un pointeur constant sur un X non constant (voir Pointers Const et Pointers to Const [7, 21]). Parce que l'objet auquel il fait référence n'est pas const, il peut être modifié. Le type de this dans une fonction membre const d'une classe X est const X * const. C’est-à-dire qu’il s’agit d’un pointeur constant sur une constante X. Comme l’objet auquel il fait référence 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;
};
8
Nan Xiao

lorsque vous utilisez const dans la signature de la méthode (comme votre dit: const char* foo() const;), vous indiquez au compilateur que la mémoire pointée par this ne peut pas être modifiée par cette méthode (foo ici).

6
Matrix Buster

Je voudrais ajouter le point suivant.

Vous pouvez aussi fairec'est un const & et const &&

Alors,

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

2
coder3101

Le mot clé const utilisé avec la déclaration de fonction spécifie qu'il s'agit d'un fonction membre const et qu'il va ne peut pas être modifié les données membres du objet.

0
Chandra Shekhar