2012-01-16 15 views
5

Tengo una clase con un miembro que no cambia con los métodos de la clase, así que la marqué como const. Mi problema es que estaba usando el operador de asignación predeterminado como un constructor de copia para evitar múltiples declaraciones. Pero en este caso, el operador de asignación no se genera automáticamente, entonces obtengo algunos errores de compilación: 'operator =' function is unavailable. Esto parece que no hay un escenario de la vida real donde los miembros de la clase const puedan ser realmente utilizados (por ejemplo, ¿has visto algún miembro de la const en el código STL?).¿Los miembros de la clase const son útiles cuando el operador de asignación está sobrecargado?

¿Hay alguna manera de solucionar esto, además de eliminar const?

EDITAR: un código

class A 
{ 
public : 
    const int size; 
    A(const char* str) : size(strlen(str)) {} 
    A() : size(0) {} 
}; 


A create(const char* param) 
{ 
    return A(param); 
} 


void myMethod() 
{ 
    A a; 

    a = create("abcdef"); 
    // do something 

    a = create("xyz"); 
    // do something 
} 
+0

He editado el título de algo que creo que describe más de cerca lo que quería hacer, y alentará a obtener más respuestas útiles. Si no está de acuerdo, siéntase libre de cambiarlo nuevamente. – Crashworks

+0

@Crashworks gracias! –

Respuesta

3

Aquí es su idea errónea que está causando este problema:

[..] que no se cambió por los métodos de la clase

La variable miembro se cambió por un método de la clase, el operador de asignación. Incluyendo el que sintetizó el compilador. Si marca una variable miembro como const, esto expresa que esta variable (¡no debería!) Cambiará su valor durante el tiempo de vida del objeto. Entonces, claramente, la asignación de un nuevo valor al objeto viola esta declaración. Entonces, si realmente no desea que el miembro cambie, simplemente no lo haga const.

1

Sí, se puede anular el operador de asignación.

Como está utilizando el predeterminado, el compilador intentará copiar también los miembros const. Lo cual es ilegal, ya que es const.

class A 
{ 
private: 
    const int a; 
public : 
    A() : a(0) {} 
    A& operator = (const A& other) {return *this;} 
}; 

int main() 
{ 
    A a; 
    A b; 
    a = b; //this is legal if operator = is declared 
} 
+2

Entonces, ¿el precio de los miembros de const es que puede proporcionar un operador de asignación, pero solo uno roto? – UncleBens

+1

@UncleBens ¿por qué está roto? No lo es, no está modificando el miembro 'const' ... que debería tener sentido, ¿no? –

+1

@UncleBens: Dado que el miembro 'const' en el lhs es probable que sea el mismo que el del' rhs', ya que está establecido solo en el constructor, no tiene sentido copiarlo. Si se inicializa de manera diferente en diferentes constructores, entonces tal vez desee reconsiderar su diseño. – Johnsyweb

2

const miembros son ideales en muchos, muchos casos. por supuesto, existe el caso obvio de que un valor no debe o no debe cambiar, pero también es una restricción importante para la optimización y concurrencia, no todo tipo necesita o debe tener un operador de asignación.

si el miembro necesita el comportamiento de asignación, entonces la variable no debe ser const.

cuando el valor/miembro no debe mutar o ser mutado por this, es más clara para proporcionar una interfaz separada para los miembros variables (o incluso un subtipo> composición en casos más complejos):

class t_text { 
public: 
// ... 
public: 
    void setString(const std::string& p); 
private: 
    const t_text_attributes d_attributes; 
    std::string d_string; 
}; 

por lo tanto, mi sugerencia es para ocultar el operador de asignación, y para hacer que el 'trozo mutable' o miembro configuración poder para mayor claridad:

text.setString("TEXT"); // << Good: What you read is what happens. 
text = otherText; // << Bad: Surprise - attributes don't actually change! 
+4

La optimización y concurrencia son las razones menos importantes para usar 'const' en las que puedo pensar. Diría que es más importante evitar que hagas cosas estúpidas forzándote a pensar (o al menos forzarte a sentirte un poco culpable por tener que desechar la constness). –

+0

@Frerich tal vez fue un error de mi parte, pero se asumió que usar 'const' por la razón más obvia. Lo actualizaré para evitar confusiones. – justin

2

No puede tener un miembro const y una asignación de soporte, al menos no la asignación con la semántica esperada. const es, lógicamente, un prometiendo que el miembro nunca cambiará, y la asignación es (implícitamente, en la mente de la mayoría de la gente) una promesa de que todos los datos miembros tomarán los valores de los miembros del lado derecho (que normalmente significa cambiar).Hay un conflicto muy definido entre estos dos promesas.

Por supuesto, muchos tipos no deberían admitir la asignación para comenzar; para los tipos que no admitan la asignación, no hay ningún problema al declarar miembro de datos const. En general, sin embargo, encontré const mucho menos útil aquí; const es parte de un contrato, y los miembros de datos son que generalmente no forman parte del contrato externo de la clase. (Sin embargo, una gran cantidad depende — si el miembro de datos es público o protegido, entonces el hecho de que es inmutable podría ser parte del contrato externo. Y de supuesto, no hay nada de malo en expresar invariantes de clase internas en las construcciones del lenguaje, cualquiera.)

+1

"No se puede" - bueno, puede, pero luego tiene que definir una asignación personalizada. Por ejemplo, un objeto asignable lógicamente asignado por X podría contener un puntero const a X, para ayudar a pedirle a X que desasigne ese objeto. Tal cosa podría resolver algunos problemas impuestos por un marco existente, por ejemplo. El puntero sería constante durante la vida útil del objeto y no se expondrá como parte del estado del objeto lógico. Es decir. no sería parte del estado asignable externamente. Saludos y hth., –

Cuestiones relacionadas