2014-10-31 6 views
4

회원 변수가 enabled_m인데 그 값은 변수의 수에 따라 다릅니다. 이러한 불변이 클래스에 의해 유지되어야하기 때문에, 나는 그것이 private 할 것을 권장합니다 작동하지만 정말 내 의도는enabled_m을 수정 에 클래스를 통해 갈 foo_t의 사용자를 필요로하는 것입니다const 연산자에 대해서만 공용 멤버 변수 public을 지정할 수 있습니까?

class foo_t 
{ 
public: 
    void set_this(...); // may affect enabled_m 
    void set_that(...); // may affect enabled_m 
    void set_the_other_thing(...); // may affect enabled_m 

    bool is_enabled() const { return enabled_m; } 

private: 
    bool enabled_m; 
}; 

합니다. 모두를 필요로하지 않고

bool my_enabled = foo.enabled_m; // OK 
foo.enabled_m = my_enabled; // Error: enabled_m is private 

가 비 const 작업 const 운영 및 private에 대한 enabled_mpublic을 만들 수있는 방법이 있나요 : 사용자가 원하는 경우, 즉 허용 작동해야
enabled_m을 읽을 단지 하기 사용자가 접근 자 루틴을 수행합니까?

+5

게터 기능을 사용하는 것이 잘못된 이유는 무엇입니까? 만약 당신의 관심이 효율적이라면,'const bool '을 반환 한'inline' 함수는 아마도 직접 멤버 액세스와 같은 것으로 컴파일 될 것입니다. – dlf

+0

"진짜"bool을 가리키는 프록시 객체를 만들 수 있습니다.하지만 그만한 가치가 있습니까? 게터가 가장 인기 있고 깨끗한 솔루션입니다. –

+0

@ dlf의 우려 사항 중, 인터페이스 이중성은 사용자가 그렇게해도 혼란스럽게 만들 것이라고 생각합니다. – Borgleader

답변

9

아니요, 회원에게만 수정을 제한 할 방법이 없습니다. private은 이름에 대한 모든 액세스를 제한합니다. const은 어디에서나 수정을 방지합니다.

그로테스크 한 대안 (예 : const 참조 또는 const_cast 참조)이 있지만 접근 자 기능은이를 수행하는 가장 단순하고 가장 관용적 인 방법입니다. 예와 같이 인라인 인 경우 직접 액세스와 같이 효율적으로 사용해야합니다.

+0

그건 내 추론이었습니다. 뭔가를 놓치지 않았 음을 확신하고 싶었습니다. – fbrereto

+0

그로테스크라는 용어는 유효한 구성을 과다하게 보인 것처럼 보입니다. 그러나 클래스의 미래 진화를 방해 할 수 있기 때문에 (f.ex 게으른 평가가되거나 다른 결정을 내리지 못함) – Christophe

+2

@Christophe : 참조 멤버를 추가하면 복사본이 손상 될 수 있으므로 의미 : 기본 복사 생성자는 잘못된 개체에 대한 참조를 제공합니다. 나는 그로테스크라고 부른다. 'const_cast'를 사용하여'const' 멤버를 수정하는 것은 UB입니다. 이것은 UB입니다. 이것은 대단히 그로테스크합니다. –

10

대부분의 엔지니어는 접근 방법을 사용하는 것을 선호하지만, 당신이 정말로 주위에 해크를 원한다면, 당신은 같은 것을 할 수있는 :

class AccessControl 
{ 
private: 
    int dontModifyMeBro; 
public: 
    const int& rDontModifyMeBro; 
    AccessControl(int theInt): dontModifyMeBro(theInt), rDontModifyMeBro(dontModifyMeBro) 
    {} 

    // The default copy constructor would give a reference to the wrong variable. 
    // Either delete it, or provide a correct version. 
    AccessControl(AccessControl const & other): 
     dontModifyMeBro(other.rDontModifyMeBro), 
     rDontModifyMeBro(dontModifyMeBro) 
    {} 

    // The reference member deletes the default assignment operator. 
    // Either leave it deleted, or provide a correct version. 
    AccessControl & operator=(AccessControl const & other) { 
     dontModifyMeBro = other.dontModifyMeBro; 
    } 
}; 
+2

참조를 올바르게 초기화하려면 기본값이 아닌 복사 생성자가 필요합니다. 할당을 허용하려면 기본값이 아닌 대입 연산자를 사용합니다. –

+3

그래, @MikeSeymour, 나는 이것이 당신이 "그로테스크 한"그룹에이 방법을 넣은 이유라고 생각한다. 당신의 대답에 +1하십시오. – iwolf

5

큰 거래는 여기에 사용할 노출시키는 노출 뒤에 의도에 따라 달라집니다 상태, 이지만 내 일반적인 조언은 에 전혀 노출되지 않도록하는 것입니다..

당신의 is_enabled의 일반적인 사용은있을 법한 : 제 생각에는

if (f.is_enabled()) 
    f.set_this(whatever); 

, 그것은 단지 set_this 전화를 거의 항상 더 나은, 그리고 (클라이언트가 관심 경우는) 그것을 표시하는 값을 반환 한 당신이 (하나의 중요한 예를 들어) 멀티 스레드 프로그래밍을 할 시작할 때

if (!f.set_this(whatever)) 
    // deal with error 

이 차이가 absolutel이되는 사소한 차이처럼 보일 수 있지만 : 클라이언트 코드가 같은 뭔가가되도록 그 여부, 성공 중요합니다. 특히 활성화 된 상태를 테스트 한 다음 값을 설정하려는 시도는 경쟁 조건에 영향을받습니다. enabled 상태는 is_enabled에 대한 호출과 set_this에 대한 호출 사이에서 변경 될 수 있습니다.

짧은 이야기를 짧게 만들려면 대개 가난한 디자인입니다. 그냥하지 마.