¿Cuál es el significado de 'const' al final de una declaración de función miembro?

Resuelto asked hace 15 años • 0 respuestas

¿ Cuál es el significado de constdeclaraciones como estas?

class foobar
{
  public:
     operator int () const;
     const char* foo() const;
};
 avatar Apr 15 '09 20:04
Aceptado

Cuando agrega la constpalabra clave a un método, el thispuntero se convertirá esencialmente en un puntero a constun objeto y, por lo tanto, no podrá cambiar ningún dato de miembro. (A menos que uses mutable, hablaremos de eso más adelante).

La constpalabra clave es parte de la firma de funciones, lo que significa que puede implementar dos métodos similares, uno que se llama cuando el objeto es consty otro que no lo es.

#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();
}

Esto generará

Foo
Foo const

En el método no constante puedes cambiar los miembros de la instancia, lo que no puedes hacer en la constversión. Si cambia la declaración del método en el ejemplo anterior al código siguiente, obtendrá algunos errores.

    void Foo()
    {
        counter++; //this works
        std::cout << "Foo" << std::endl;    
    }

    void Foo() const
    {
        counter++; //this will not compile
        std::cout << "Foo const" << std::endl;
    }

Esto no es completamente cierto, porque puede marcar un miembro como mutabley constluego un método puede cambiarlo. Se usa principalmente para contadores internos y esas cosas. La solución para eso sería el siguiente código.

#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;
}

que daría salida

Foo
Foo const
Foo has been invoked 2 times
Mats Fredriksson avatar Apr 15 '2009 13:04 Mats Fredriksson

La constante significa que el método promete no alterar ningún miembro de la clase. Podrías ejecutar los miembros del objeto que están así marcados, incluso si el objeto en sí estuviera marcado const:

const foobar fb;
fb.foo();

sería legal.

Consulte ¿Cuántos y cuáles son los usos de "const" en C++? para más información.

Blair Conrad avatar Apr 15 '2009 13:04 Blair Conrad

El constcalificador significa que los métodos se pueden invocar con cualquier valor de foobar. La diferencia surge cuando consideras llamar a un método no constante en un objeto constante. Considere si su foobartipo tenía la siguiente declaración de método adicional:

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

El método bar()no es constante y solo se puede acceder a él desde valores no constantes.

void func1(const foobar& fb1, foobar& fb2) {
  const char* v1 = fb1.bar();  // won't compile
  const char* v2 = fb2.bar();  // works
}

Sin embargo , la idea detrás constes marcar métodos que no alterarán el estado interno de la clase. Este es un concepto poderoso pero en realidad no se puede aplicar en C++. Es más una promesa que una garantía. Y uno que a menudo se rompe y se rompe fácilmente.

foobar& fbNonConst = const_cast<foobar&>(fb1);
JaredPar avatar Apr 15 '2009 13:04 JaredPar

Estas constantes significan que el compilador generará un error si el método 'con const' cambia los datos internos.

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_;
};

La prueba

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
}

Lee esto para más información

Mykola Golubyev avatar Apr 15 '2009 13:04 Mykola Golubyev

La respuesta de Blair es acertada.

Sin embargo, tenga en cuenta que hay un mutablecalificador que se puede agregar a los miembros de datos de una clase. Cualquier miembro así marcado puede modificarse en un constmétodo sin violar el constcontrato.

Es posible que desee utilizar esto (por ejemplo) si desea que un objeto recuerde cuántas veces se llama a un método en particular, sin afectar la consistencia "lógica" de ese método.

Alnitak avatar Apr 15 '2009 13:04 Alnitak