2011-11-30 8 views
8

Tengo un método const en mi clase, que no se puede cambiar a non-const. En este método, necesito llamar a un método no const pero el compilador no me deja hacer eso.Cómo llamar a un método no const desde un método const?

¿Hay alguna forma de evitarlo? Este es un ejemplo simplificado de mi código:

int SomeClass::someMethod() const { 
    QColor saveColor = color(); 
    setColor(QColor(255,255,255)); // Calling non-const method 

    // .... 

    setColor(saveColor); // restore color 

    return 1; 
} 
+3

¿No sería contrario a la regla cardinal de ser una función const? – DumbCoder

+2

@DumbCoder, desde el exterior, es una función constante porque no se ha modificado nada visible para el cliente. –

+0

Un método no const implica que está cambiando algunos datos en su objeto. Si 'someMethod()' llama a un método no const, entonces está cambiando indirectamente los datos. Entonces realmente, 'someMethod()' simplemente no debería ser 'const'. –

Respuesta

5

Uno de los desafíos de hacer const -corrección es que no puede hacerlo a la mitad. Es todo o nada. Si tratas de hacerlo a mitad de camino, terminas en un lugar difícil como el que estás aquí. Usted termina con una buena clase const -correct que está siendo usada por algún viejo código loco, típicamente heredado (o escrito por un viejo crummudgeon) que no es const -correcto y simplemente no funciona. Usted se pregunta si const -corrección vale la pena todo el problema.

I need to call a non-const method [from a const method] 

No se puede - no directamente. Tampoco deberías. Sin embargo, existe una alternativa ...

Obviamente, no puede llamar a un método que no sea const desde un método const. De lo contrario, const no tendría ningún significado cuando se aplica a funciones miembro.

Una función de miembro const puede cambiar las variables de miembro marcadas mutable, pero ha indicado que esto no es posible en su caso.

Se podría tratar de esparcir const Ness haciendo algo como SomeClass* me = const_cast<SomeClass*>(this); pero A) Normalmente, esto dará lugar a la UB, o 2) Se viola la idea de const -correctness.

Una cosa que podría hacer, si lo que realmente está tratando de lograr sería soportar esto, es crear un objeto proxy no const, y no hacer const -y cosas con eso. A saber:

#include <iostream> 
#include <string> 
using namespace std; 

class Gizmo 
{ 
public: 
    Gizmo() : n_(42) {}; 
    void Foo() const; 
    void Bar() { cout << "Bar() : " << n_ << "\n"; } 
    void SetN(int n) { n_ = n; }; 
    int GetN() const { return n_; } 
private: 
    int n_; 
}; 

void Gizmo::Foo() const 
{ 
    // we want to do non-const'y things, so create a proxy... 
    Gizmo proxy(*this); 
    int save_n = proxy.GetN(); 
    proxy.SetN(save_n + 1); 
    proxy.Bar(); 
    proxy.SetN(save_n); 
} 

int main() 
{ 
    Gizmo gizmo; 
    gizmo.Foo(); 
} 
+0

¿Cómo es útil? Estoy confundido. El proxy aquí no es un proxy, ya que no representa el objeto original. Es solo un objeto local sin ningún poder extraordinario. Trabajar con proxy no es equivalente a trabajar con el objeto original. – Nawaz

+2

@nawaz: si ayuda a hacer su trabajo de forma estándar, es útil. –

11

usted podría utilizar const_cast en this puntero,

int SomeClass::someMethod() const { 
    const_cast<SomeClass*>(this)->setColor(...);// Calling non-const method 
    //whatever 
} 

pero si lo hace que para un objeto que fue declarada originalmente const se encuentra con un comportamiento indefinido.

Así que esto:

SomeClass object; 
object.someMethod(); 

está bien, pero esto:

const SomeClass object; 
object.someMethod(); 

produce un comportamiento indefinido.

La verdadera solución es que su función const no debe ser const en primer lugar.

+1

Supongo que se podría usar una fábrica y constructores privados para garantizar que no haya instancias 'const' de' SomeClass'. Pero a menos que eso ya esté allí, es un cambio mucho mayor en la interfaz de clase que los cambios que el interrogador tiene prohibido hacer, por lo que probablemente no sea de mucha ayuda. –

5

Cómo llamar a un método no const desde un método const?

No debe. Puede ejecutar un comportamiento indefinido si descarta la const-ness de this, usando const_cast. El uso de const_cast cerrará la boca del compilador, pero eso no es una solución. Si necesita hacerlo, significa que la función const no debe ser const en primer lugar. Que sea no const.

O bien, debe hacer otra cosa, que no requiera llamar a la función no const desde la función const. Al igual que, no llame a la función setColor? Como, divide la función const en más de una función (si puedes hacer eso)? ¿O algo mas?

En su caso particular, si setColor sólo establece una variable miembro, dicen m_color, entonces se puede declarar que mutable:

mutable QColor m_color; 

y luego ponerlo en su función const, sin llamar setColor función, y sin haciendo const_cast.

+0

Esa no es una respuesta a la pregunta, ya que acabo de escribir. No puedo cambiarlo a no const. –

+0

@Laurent: mira la edición. – Nawaz

+2

@Laurent, potencialmente podrías, si pudieras hacer que los miembros tocados en esa función 'mutable'? – Nim

6

Si necesita cambiar algún estado interno dentro de un const -method también se puede declarar el estado afectado mutable:

class Foo { 
public: 
    void doStuff() const { bar = 5; } 
private: 
    mutable int bar; 
}; 

Esto está pensado para casos donde hay cosas como mutex como los miembros de su clase. La adquisición y liberación de un mutex no afecta el estado visible del cliente, pero está técnicamente prohibido en un método const. La solución es marcar el mutex mutable. Su caso se ve similar, aunque creo que su clase requiere alguna refacturación para que esta solución sea aplicable.

También, es posible que desee leer this answer para ver cómo puede hacer que esta excepción temporal de cambio de estado sea segura usando RAII.

Cuestiones relacionadas