const antes del parámetro vs const después del nombre de la función c ++

86

¿Cuál es la diferencia entre algo como esto?

friend Circle copy(const Circle &);

y algo como esto

friend Circle copy(Circle&) const;

Sé que const después de que la función se usa para decirle al compilador que esta función no intentará cambiar el objeto al que se llama, ¿qué pasa con el otro?

jazzybazz
fuente
6
que no cambiará el parámetro es el otro
Chad

Respuestas:

194

La primera forma significa que el (estado del) Circleobjeto vinculado a la referencia que es el parámetro de la copy()función no será alterado por copy()esa referencia. La referencia es una referencia a const, por lo que no será posible invocar funciones miembro de a Circletravés de esa referencia que no estén calificadas como const.

La segunda forma, por otro lado, es ilegal: solo las funciones miembro pueden ser const-calificadas (mientras que lo que está declarando es una friendfunción global ).

Cuando constcalifica una función miembro, la calificación se refiere al thisargumento implícito . En otras palabras, a esa función no se le permitirá alterar el estado del objeto en el que se invoca (el objeto al que apunta el thispuntero implícito ), con la excepción de los mutableobjetos, pero esa es otra historia.

Para decirlo con código:

struct X
{
    void foo() const // <== The implicit "this" pointer is const-qualified!
    {
        _x = 42; // ERROR! The "this" pointer is implicitly const
        _y = 42; // OK (_y is mutable)
    }

    void bar(X& obj) const // <== The implicit "this" pointer is const-qualified!
    {
        obj._x = 42; // OK! obj is a reference to non-const
        _x = 42; // ERROR! The "this" pointer is implicitly const
    }

    void bar(X const& obj) // <== The implicit "this" pointer is NOT const-qualified!
    {
        obj._x = 42; // ERROR! obj is a reference to const
        obj._y = 42; // OK! obj is a reference to const, but _y is mutable
        _x = 42; // OK! The "this" pointer is implicitly non-const
    }

    int _x;
    mutable int _y;
};
Andy Prowl
fuente
11
¡Helluva responde! ¡Gracias!
SexyBeast
1
Entonces, para el segundo caso, si tengo un constobjeto objde clase Xy llamo bar()como obj.bar(obj), ¿qué se supone que debe suceder y por qué? ¿No debería obj._x = 42fallar, ya que objse declara consten el llamador?
SexyBeast
1
¿Qué pasa con el caso en el que hace que la última función de barra ( void bar(X const& obj) {...}) se vea así? void bar(const X& obj) {...}, ¿mover la constpalabra clave a esta ubicación cambia algo? Si es así, ¿puede agregar este ejemplo también, por favor?
Gabriel Staples
1
@GabrielStaples Son lo mismo; constse aplica a lo que está a su izquierda, oa lo que está a su derecha en caso de que no haya nada a la izquierda. En su caso, verá que para ambas versiones constse aplica a X.
Andreas Flöjt
69

Los métodos de la clase C ++ tienen un thisparámetro implícito que viene antes que todos los explícitos. Entonces, una función declarada dentro de una clase como esta:

class C {
  void f(int x);

Puedes imaginar que realmente se ve así:

  void f(C* this, int x);

Ahora, si lo declaras de esta manera:

  void f(int x) const;

Es como si escribieras esto:

  void f(const C* this, int x);

Es decir, el final consthace que el thisparámetro sea const, lo que significa que puede invocar el método en objetos const del tipo de clase y que el método no puede modificar el objeto en el que fue invocado (al menos, no a través de los canales normales).

John Zwinck
fuente
2
Perfectamente correcto, sin embargo, no responde a la pregunta, que en realidad no se refiere a un método de clase sino a una función de amigo.
mah
5
Sí, elegí ignorar la friendparte porque creo que en realidad es irrelevante para la pregunta real del OP (o cuál será la pregunta real una vez que todos los problemas salgan a la luz). Que así sea.
John Zwinck
Creo que es un poco engañoso decir "puedes invocar el método en objetos constantes del tipo de clase" porque puedes invocar el método const en objetos constantes o no constantes, mientras que las funciones no constantes solo pueden ser llamadas por objetos no constantes. de lo contrario, esta es mi respuesta favorita
csguy
8
Circle copy(Circle&) const;

hace la función en constsí. Esto solo se puede usar para funciones miembro de una clase / estructura.

Hacer que un miembro funcione constsignifica que

  • no puede llamar a ninguna función miembro que no sea constante
  • no puede cambiar ninguna variable miembro.
  • puede ser llamado por un constobjeto (los constobjetos solo pueden llamar a constfunciones). Los objetos que no son constantes también pueden llamar a una constfunción.
  • Se debe ser función miembro de la clase ' círculo '.

Ahora considere el siguiente:

Circle copy(const Circle &);

mientras que este significa que el parámetro pasado no se puede cambiar dentro de la función. Puede ser o no una función miembro de la clase.

NOTA: Es posible sobrecargar una función de tal manera que tenga una constversión no constante de la misma función.

Waqar
fuente
7

ACLAMAR TODA LA CONFUSIÓN RELACIONADA CON const


constvino de un significado constante que algo no se puede cambiar sino que se puede leer.

  1. si calificamos nuestra variable con constpalabra clave, no podemos cambiarla más tarde.
    por ejemplo, la variable const debe inicializarse cuando se declara.
    constint var =25;
    var =50; // gives error

  2. si calificamos nuestra variable de puntero con after, entonces no podemos cambiar el puntero en sí, pero el contenido del puntero se puede cambiar . por ejemplo, // peroconst *

    int *const ptr = new int;
    ptr = new int; //gives error

    *ptr=5445; //allowed

  3. Si calificamos nuestra variable puntero con antes , entonces podemos cambiar el puntero en sí, sino el contenido del puntero se no se puede cambiar . por ejemplo, // peroconst *

    intconst* ptr = new int(85);
    //or
    constint * ptr = new int(85);
    ptr = new int; // allowed

    *ptr=5445; // gives error

  4. puntero y contenido ambos constantes,
    por ejemplo
    intconst*constptr = new int(85);
    //or
    constint *constptr = new int(85);
    ptr = new int; // not allowed
    *ptr=5445; // not allowed


  1. Circle copy(const Circle &);
    aquí const Circle significa que el valor de Circle solo es legible, si intentamos cambiar el valor de la función Circle inside, da error.
  2. friend Circle copy(Circle&) const;
    Este tipo de función no es para variables no miembro. Se usa para clases o estructuras. Aquí toda la función está calificada con la palabra clave const, lo que significa que no podemos cambiar la variable miembro del objeto . p.ej
    class A{ public :
              int  var;
              void fun1()
                    { var = 50; // allowed
                    } 
              void fun2()const
                       { var=50; //not allowed
                       }
           }; 
Ramesh Choudhary
fuente
4

Uno se refiere al parámetro y el otro a la función.

Circle copy(const Circle &);

Esto significa que el parámetro pasado no se puede cambiar dentro de la función

Circle copy(Circle&) const;

La constfunción calificada se usa para funciones miembro y significa que no puede cambiar los miembros de datos del objeto en sí. El ejemplo que publicaste no tenía sentido.

Leer de derecha a izquierda

Si reescribimos la primera función como Circle copy(Circle const&);, lo que significa lo mismo, queda claro que leer de derecha a izquierda se vuelve útil. copyes una función que toma una constreferencia a un Circleobjeto y devuelve un Circleobjeto por referencia.

Alex Chamberlain
fuente
0

friend Circle copy(const Circle &);// se refiere al parámetro constante de la función. No puedo cambiar el valor almacenado por parámetro.

Necesita eliminar amigo en su copia de círculo de ejemplo (Circle &) const; // no se puede cambiar este valor poniter nombrado como función miembro constante

shivakumar
fuente
-1
friend Circle copy(const Circle &);

El valor del parámetro no se cambiará durante las llamadas a la función.

friend Circle copy(const Circle &)const ; 

La función es un descriptor de acceso que no cambia ningún valor de los miembros de la clase. Generalmente, existen varios tipos de funciones: accesores y mutadores. Accesor: examina pero no cambia el estado de su objeto.

Sam
fuente