2008-11-16 16 views
10
class String 
{ 

    private: 
     char* rep; 

    public: 
     String (const char*); 
     void toUpper() const; 
}; 


String :: String (const char* s) 
{ 
    rep = new char [strlen(s)+1]; 
    strcpy (rep, s); 
} 


void String :: toUpper() const 
{ 
    for (int i = 0; rep [i]; i++) 
    rep[i] = toupper(rep[i]); 
} 


int main() 
{ 
    const String lower ("lower"); 
    lower.toUpper(); 

    cout << lower << endl; 
    return 0; 
} 

Respuesta

19

Un método constante, es una función miembro que no muta sus variables miembro.

const en una función miembro no implica const char *. Lo que significaría que no puede cambiar los datos en la dirección que contiene el puntero.

Su ejemplo no muta las variables de los miembros.

Const en una función de miembro, se asegurará de tratar todas las variables de miembro como const.

Esto significa que si usted tiene:

int x; 
char c; 
char *p; 

entonces usted tendrá que:

const int x; 
const char c; 
char * const p; //<-- means you cannot change what p points to, but you can change the data p points to 

Hay 2 tipos de punteros const. Una función miembro miembro usa la que he enumerado arriba.


Una manera de obtener el error que desea:

pruebe a cambiar:

char * rep; 

a:

char rep[1024]; 

Y elimine esta línea:

rep = new char [strlen(s)+1]; 

Se lanzará el error que está esperando (no se puede modificar porque los miembros de palabra clave const)

Porque sólo hay 1 tipo de matriz const. Y eso significa que no puedes modificar ninguno de sus datos.


Ahora todo el sistema es en realidad roto con el siguiente ejemplo:

class String 
{ 

    private: 
     char rep2[1024]; 
     char* rep; 

... 


String :: String (const char* s) 
{ 
    rep = rep2; 
    strcpy (rep, s); 
} 

Así que la lección a aprender aquí es que la palabra clave const en funciones miembro no asegura que el objeto no cambiará en absoluto.

Solo garantiza que cada variable miembro se tratará como const. Y para los indicadores, hay una gran diferencia entre const char * y char * const.

La mayor parte del tiempo una función miembro miembro significa que la función miembro no modificará el objeto en sí, pero este no es siempre el caso, como se muestra en el ejemplo anterior.

+0

Muchas gracias por la respuesta rápida y la delineación muy ordenada. Stack Overflow realmente rocas – mahesh

1

toUpper() no cambia el puntero (que pertenece a la clase). Solo cambia los datos a los que señala rep (que no pertenecen a la clase).

Sin embargo, 'const' es una especie de garantía para los usuarios de su clase: si se declara un método const, quien usa una instancia de su clase puede esperar que no cambie al llamar al método. Mi punto es que si toUpper() cambia el estado de una cadena, no lo declare, ya sea que C++ lo permita o no.

1

El calificador const significa que no cambiará ningún miembro de la clase.

En este caso rep es el único miembro de la clase y no veo ningún intento de modificar este miembro. Cualquier cosa apuntada a o con referencia fuera de la clase no se considera como parte de la clase.

Una solución a este problema sería reemplazar el char * con std :: string.
Entonces sólo sería capaz de llamar a los miembros de const std :: string desde dentro toUpper()

Por ejemplo (uso std :: string)

class String 
{ 
    std::string rep; 

    void toUpper() const 
    { 
     for (int i = 0; rep [i]; i++) 
      rep[i] = toupper(rep[i]); 

     // Can only use const member functions on rep. 
     // So here we use 'char const& std::string::operator[](size_t) const' 
     // There is a non const version but we are not allowed to use it 
     // because this method is const. 

     // So the return type is 'char const&' 
     // This can be used in the call to toupper() 
     // But not on the lhs of the assignemnt statement 

    } 
} 
4

La razón es que no cambia rep. Si lo hiciera, encontraría rep = ...; en algún lugar de su código. Esta es la diferencia entre

char*const rep; 

y

const char* rep; 

En su caso, el primero se realiza si se ejecuta un miembro de función const: El puntero es const. Por lo tanto, no podrá restablecer el puntero. Pero muy bien podrá cambiar a lo que apunta el puntero.

Ahora, recuerde rep[i] = ...; es lo mismo que *(rep + i) = ...;. Por lo tanto, lo que cambie no es el puntero, sino lo que el puntero apunta a. Está permitido, ya que el puntero no es del segundo tipo de caso.

Solución

  1. La const lo que significa que está viendo es physical constness. Sin embargo, una función de miembro const significa que su objeto es logical const. Si un cambio en algún contenido cambiará el constness lógica de su objeto, por ejemplo, si cambia alguna variable estática de la que depende su objeto, su compilador no puede saber que su clase ahora tiene otro valor lógico.Y tampoco puede saber que el valor lógico cambia dependiendo de a qué apunta un puntero: El compilador no intenta verificar la constidad lógica en una función de miembro constante, ya que no puede saber lo que significan esas variables miembro. Esto se denomina const-correctness.
  2. Use un objeto que no sea solo una referencia o un puntero: una función de miembro const hará que ese objeto sea const, y no le permitirá cambiar su contenido. std::string, tal como lo propusieron algunos, o una matriz de caracteres (tenga en cuenta que una matriz le impedirá cambiar su contenido, en lugar de solo un puntero), sería una opción adecuada.
  3. 2.
1

No se puede cambiar el valor de algo declarada como

const char* rep; 

o

const char* const rep; 

Desafortunadamente, declarando su const miembro se convierte en representante en

char* const rep; 

lo que significa que no puedes c cuelgue la dirección acutal, pero puede cambiar el contenido, mientras que no puede cambiar el valor.

Para hacer que los const memebrs respeten mantener su const buffer, tendrá que hacer rep y una matriz de caracteres o un objeto de cadena en lugar de un puntero de carácter.

Cuestiones relacionadas