2011-11-30 2 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의 정답을 해결하는 중 하나는 반쯤 할 수 없다는 것입니다. 그것은 모두 또는 아무것도 아닙니다. 중간에 그걸하려고하면 여기있는 것처럼 힘든 자리에 들게됩니다. 좋은 const -correct class는 const -correct가 아닌 보통의 레거시 코드 (또는 오래된 crummudgeon으로 작성된 코드)에 의해 사용되고 있으며 작동하지 않습니다. const - 정정이 모든 문제의 가치가 있는지 궁금하게 남았습니다.

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

직접하실 수 없습니다. 너도 그래. 그러나 대안이 있습니다 ...

분명히 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 : op가 표준에 부합하는 방식으로 작업을 완료하는 데 도움이된다면 유용합니다. –

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-ness를 버리면 정의되지 않은 동작이 발생할 수 있습니다. const_cast의 사용법은 컴파일러의 입을 막을 것이지만 해결책은 아닙니다. 당신이해야한다면, const 함수가 처음에 const이되어서는 안된다는 것을 의미합니다. 그것을 비 const로 만드십시오.

또는 다른 작업을 수행해야합니다. const 함수에서 const가 아닌 함수를 호출 할 필요가 없습니다. 마찬가지로 setColor 기능을 호출하지 마십시오? 마찬가지로, const 함수를 둘 이상의 함수로 분할하십시오 (그렇게 할 수 있다면)? 또는 다른 것?

mutable QColor m_color; 

을 다음 setColor 함수를 호출하지 않고, 당신의 CONST 기능에서 설정하고,없는 : 일부 멤버 변수를 설정 setColor 경우 특정 경우

는, m_color 말, 당신은 그것을 mutable를 선언 할 수 있습니다 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을 읽어 볼 수 있습니다.

관련 문제