2011-11-30 28 views
8

クラスにconstメソッドがあります。これは非constに変更することはできません。このメソッドでは、非constメソッドを呼び出す必要がありますが、コンパイラは私にそれをさせません。constメソッドから非constメソッドを呼び出す方法は?

周辺には何もありませんか?ここに私のコードの単純化されたサンプルです:

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

    // .... 

    setColor(saveColor); // restore color 

    return 1; 
} 
+3

const関数であるという基本ルールに反していませんか? – DumbCoder

+2

@DumbCoder、外部からは、クライアントに見えるものは何も変更されていないという点でconst関数です。 –

+0

非constメソッドは、オブジェクト内の一部のデータが変更されていることを意味します。 'someMethod()'が非constメソッドを呼び出すと、それは間接的にデータを変更しています。だから、本当に 'someMethod()'は単に 'const'であってはいけません。 –

答えて

5

const - 正解の課題の1つは、途中で行うことができないことです。それはすべてか何かのどちらかです。途中でやろうとすると、あなたがここにいるような厳しい場所で終わる。あなたは良いconst - 正しいクラスは、const - 正しいものではありませんいくつかのクレイジー古い、一般的には古い(古いcrummudgeonによって書かれた)コードで使用されていると終わるだけで動作しません。 const - 正解がすべての問題の価値があるかどうか疑問に思うままになります。

​​

直接できません。あなたもそうではありません。しかし、別の方法があります...

明らかに、constメソッドから非constメソッドを呼び出すことはできません。さもなければ、constはメンバー機能に適用されるとき意味を持たないでしょう。

constメンバ関数は、mutableという名前のメンバ変数を変更できますが、これはあなたのケースでは不可能であることを示しています。

あなたはSomeClass* me = const_cast<SomeClass*>(this);ような何かを行うことによって、離れconstネスをキャストしようとする可能性がありますがA)これは通常、UBになり、または2)それはconst -correctnessの全体的なアイデアに違反します。

あなたが実際に達成しようとしていることがこれをサポートするならば、constプロキシオブジェクトを作成し、それ以外のものをconst -yとすることです。それには:

#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

どのように便利ですか?よくわかりません。ここのプロキシはプロキシではありません。プロキシは元のオブジェクトを表していないからです。それは、特別な力を持たない単なるローカルオブジェクトです。プロキシを使って作業することは、元のオブジェクトで作業することと同じではありません。 – Nawaz

+2

@nawaz:もし彼が標準に準拠した方法で作業を終わらせることができれば、それは便利です。 –

11

あなたは、thisポインタにconst_castを使用

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

いますが、もともとあなたは未定義の動作に実行const宣言されたオブジェクトのためにそれを行う場合があります。

ので、この:

SomeClass object; 
object.someMethod(); 

は大丈夫ですが、この:

const SomeClass object; 
object.someMethod(); 

は、未定義の動作が得られます。

実際の解決策は、constの機能が最初にconstであってはならないということです。

+1

'SomeClass'の' const'インスタンスがないことを保証するために、私はファクトリとプライベートコンストラクタを使うことができます。しかし、それが既に存在しない限り、質問者が禁止する変更よりもクラスインターフェースの方がはるかに大きく変更されています。 –

5

constメソッドから非constメソッドを呼び出す方法はありますか?

すべきではありません。 const_castを使用して、constの定数を取り除くと、未定義の動作になる可能性があります。 const_castの使用は、コンパイラの口を閉めますが、それは解決策ではありません。あなたがする必要がある場合、const関数は最初にconstであってはならないことを意味します。それを非constにします。

または、何かを行う必要があります。これは、const関数から非const関数を呼び出す必要はありません。同様に、setColor関数を呼び出さないでください?同様に、const関数を2つ以上の関数に分割する(そうすることができれば)?または、他の何か?あなたの特定のケースで

setColorは一部だけメンバ変数を設定した場合、m_colorを言って、あなたはそれmutable宣言することができます。その後、

mutable QColor m_color; 

setColor機能を呼び出すことなく、あなたのconst関数内でそれを設定し、なしconst_castを実行しています。

+0

私はちょうど私が非constに変更することはできないと書いているように、それは質問への答えではありません。 –

+0

@Laurent:編集を参照してください。 – Nawaz

+2

@Laurent、もしあなたがそのメンバをその関数で変更可能にすることができれば、可能でしょうか? – Nim

6

あなたはまた、影響を受けた状態mutable宣言することができます-method const内のいくつかの内部状態を変更する必要がある場合:これは、あなたのクラスのメンバーとして、ミューテックスのようなものを持っている例を対象とし

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

を。ミューテックスの取得と解放はクライアントが見ることのできる状態には影響しませんが、constの方法では技術的に禁止されています。解決策は、mutexをmutableとマークすることです。あなたのケースも同様ですが、このソリューションを適用するにはリファクタリングが必要です。

また、RAIIを使用してこの一時的な状態変更例外を安全にする方法については、this answerを参照してください。

関連する問題