2011-11-30 4 views
8

Ho un metodo const nella mia classe, che non può essere modificato in non-const. In questo metodo, ho bisogno di chiamare un metodo non const, ma il compilatore non mi permette di farlo.Come chiamare un metodo non const da un metodo const?

C'è un modo per aggirarlo? Ecco un esempio semplificato del mio codice:

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

    // .... 

    setColor(saveColor); // restore color 

    return 1; 
} 
+3

Non sarebbe contro la regola cardinale di essere una funzione const? – DumbCoder

+2

@DumbCoder, dall'esterno, è una funzione const in cui non è stato modificato nulla visibile al client. –

+0

Un metodo non const implica che sta modificando alcuni dati nell'oggetto. Se 'someMethod()' chiama un metodo non const, allora sta modificando indirettamente i dati. Quindi in realtà 'someMethod()' semplicemente non dovrebbe essere 'const'. –

risposta

5

Una delle sfide da fare const -corretta è che non è possibile farlo a metà. È tutto o niente. Se provi a farlo a metà strada, finisci in un punto difficile come sei qui. Si finisce con una bella classe const -corretta usata da un vecchio pazzo, tipicamente legacy (o scritto da un vecchio crummudgeon) che non è const -corretto e semplicemente non funziona. Ti stai chiedendo se vale la pena correggere la correttezza const.

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

Non è possibile - non direttamente. Né dovresti. Tuttavia, esiste un'alternativa ...

Ovviamente non è possibile chiamare un metodo non const da un metodo const. Altrimenti, const non avrebbe alcun significato se applicato alle funzioni membro.

Una funzione membro const può modificare le variabili membro contrassegnate con mutable, ma è stato indicato che ciò non è possibile nel tuo caso.

Si potrebbe tentare di gettare via const ness facendo qualcosa di simile, ma SomeClass* me = const_cast<SomeClass*>(this); A) Questo in genere si tradurrà in UB, o 2) che viola l'intera idea di const -correctness.

Una cosa che potresti fare, se quello che stai davvero cercando di ottenere sarebbe di supporto, è creare un oggetto proxy non- const e fare cose non const -y con quello. A:

#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

Come è utile? Non ho capito bene. Il proxy qui non è un proxy, poiché non rappresenta l'oggetto originale. È solo un oggetto locale senza poteri straordinari. Lavorare con il proxy non equivale a lavorare con l'oggetto originale. – Nawaz

+2

@nawaz: se aiuta a svolgere il proprio lavoro in modo conforme allo standard, è utile. –

11

Si potrebbe utilizzare const_cast su this puntatore,

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

, ma se lo fai per un oggetto che era originariamente dichiarato const si esegue in un comportamento indefinito.

Quindi questo:

SomeClass object; 
object.someMethod(); 

va bene, ma questo:

const SomeClass object; 
object.someMethod(); 

cede comportamento non definito.

La vera soluzione è che la tua funzione const non dovrebbe essere const in primo luogo.

+1

Suppongo che si possa usare un costruttore e costruttori privati, per assicurarsi che non ci siano istanze 'const' di' SomeClass'. Ma a meno che non sia già lì, è un cambiamento molto più grande dell'interfaccia di classe rispetto alle modifiche che l'utente non è autorizzato a fare, quindi probabilmente non molto aiuto. –

5

Come chiamare un metodo non const da un metodo const?

Non si dovrebbe. Potresti imbatterti in comportamenti non definiti se elimini la costanza di this, utilizzando const_cast. L'uso di const_cast chiuderà la bocca del compilatore, ma non è una soluzione. Se è necessario, significa che la funzione const non dovrebbe essere const in primo luogo. Rendilo non const.

Oppure, si dovrebbe fare qualcos'altro, che non richiederebbe di chiamare la funzione non const dalla funzione const. Ad esempio, non chiamare la funzione setColor? Come, dividi la funzione const in più di una funzione (se puoi farlo)? O qualcos'altro?

Nel tuo caso particolare, se setColor imposta solo alcuni variabile membro, dicono m_color, allora si può dichiarare mutable:

mutable QColor m_color; 

e poi impostarlo nella funzione const, senza chiamare setColor funzione, e senza facendo const_cast.

+0

Questa non è una risposta alla domanda, come ho appena scritto non posso cambiarlo in non-const. –

+0

@Laurent: vedere la modifica. – Nawaz

+2

@Laurent, potenzialmente potresti, se potessi far toccare i membri in quella funzione 'mutabile'? – Nim

6

Se avete bisogno di cambiare un po 'di stato interno all'interno di una const -Metodo si può anche dichiarare lo stato colpito mutable:

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

questo è inteso per i casi in cui si dispone roba come i mutex come membri della tua classe. L'acquisizione e il rilascio di un mutex non influisce sullo stato client-visible, ma è tecnicamente vietato in un metodo const. La soluzione è contrassegnare il mutex mutable. Il tuo caso sembra simile, anche se penso che la tua classe richieda un refactoring per rendere applicabile questa soluzione.

Inoltre, è possibile leggere this answer per vedere come è possibile rendere provvisoria questa modifica temporanea delle eccezioni utilizzando RAII.