보호 된 멤버 변수를 사용해야합니까?


97

보호 된 멤버 변수를 사용해야합니까? 장점은 무엇이며 이로 인해 어떤 문제가 발생할 수 있습니까?

답변:


74

보호 된 멤버 변수를 사용해야합니까?

상태를 숨기는 것에 대해 얼마나 까다로운 지에 따라 다릅니다.

  • 내부 상태의 유출을 원하지 않는 경우 모든 멤버 변수를 private으로 선언하는 것이 좋습니다.
  • 하위 클래스가 내부 상태에 액세스 할 수 있다는 사실에 관심이 없다면 protected로 충분합니다.

개발자가 함께 와서 클래스를 하위 클래스로 지정하면 완전히 이해하지 못하기 때문에 엉망이 될 수 있습니다. 공용 인터페이스가 아닌 개인 멤버를 사용하면 작업이 수행되는 방식에 대한 구현 특정 세부 사항을 볼 수 없으므로 나중에 변경할 수있는 유연성을 제공합니다.


1
get / set 메서드를 사용하여 보호 된 변수와 개인용 변수의 성능에 대해 언급 할 수 있습니까?
— Jake

3
프로파일 링을 통해 병목이 접근 자 (거의 결코 그렇지 않음)가된다는 것을 알지 못한다면 걱정할 가치가 없다고 말하고 싶습니다. 문제가 될 경우 JIT를 더 현명하게 만들 수있는 트릭이 있습니다. 예를 들어 Java에서는 접근자를 최종으로 표시하여 인라인 될 수 있음을 힌트 할 수 있습니다. 솔직히 게터와 세터의 성능은 시스템 구성과 프로파일 러가 결정한 실제 성능 문제를 다루는 것보다 훨씬 덜 중요합니다.
— Allain Lalonde

23
@Jake : 성능 가정을 기반으로 디자인 결정을 내리면 안됩니다. 최고의 디자인이라고 생각하는 것을 기반으로 디자인 결정을 내리고 실제 프로파일 링에서 디자인에 병목 현상이 나타나는 경우에만 가서 수정합니다. 일반적으로 디자인이 건전하면 성능도 좋습니다.
— Mecki

공용 인터페이스가 아닌 개인 멤버를 사용하면 구현 특정 세부 정보를 볼 수 없습니다 . 클래스를 열고 조회 할 수 있으므로 말이되지 않습니까?!
— Black

2
@Black Clearly Allain은 해당 멤버에 ' 액세스 할 수 없으므로 '해당 멤버에 대해 코드를 작성할 수 없으므로 클래스 작성자가 나중에 보호 된 멤버를 자유롭게 제거 / 변경할 수 있음을 의미했습니다. (물론 pimpl 관용구를 사용하면 헤더를 포함한 번역 단위에서 시각적으로 숨길 수 있습니다.)
— underscore_d

31

요즘 일반적인 느낌은 파생 클래스와 그 기반 사이에 과도한 결합을 유발한다는 것입니다.

보호 된 메서드 / 속성에 비해 특별한 이점이 없으며 (한때 약간의 성능 이점이있을 수 있음), 매우 깊은 상속이 유행하던 시대에 더 많이 사용되었지만 현재는 그렇지 않습니다.


2
안 no particular advantage over protected methods/properties될 no particular advantage over *private* methods/properties?
— Penghe Geng 2014

아니요, 파생 클래스와 해당 기반 간의 다양한 통신 방법의 장점 / 단점에 대해 이야기하고 있었기 때문에 이러한 모든 기술은 '보호'될 것입니다. 차이점은 멤버 변수 (필드)인지 속성 / 메소드 ( 즉, 어떤 종류의 서브 루틴).
— Will Dean

1
빠른 설명에 감사드립니다. 6 년 된 게시물에 대한 내 질문에 대한 원래 포스터의 답변을 한 시간 안에 받게되어 기쁩니다. 대부분의 다른 온라인 포럼에서는 이런 일이 일어날 수 없다고 생각합니다. :)
— Penghe Geng 2014

9
더 놀라운 아직도 내가 실제로 ... 시간의 양을 통해 자신에 동의한다는 것입니다
— 윌 딘

생성자의 업무 순서 중 하나는 모든 상태 변수가 명시 적으로 초기화되었는지 확인하는 것입니다. 이 규칙을 준수하면 super구성을 사용 하여 부모 생성자를 호출 할 수 있습니다 . 그런 다음 부모 클래스에서 개인 상태 변수를 초기화합니다.
— ncmathsadist

31

일반적으로 의도적으로 공개 된 것으로 간주되지 않은 내용은 비공개로 설정합니다.

파생 클래스에서 해당 개인 변수 또는 메서드에 액세스해야하는 상황이 발생하면 개인에서 보호로 변경합니다.

이것은 거의 발생하지 않습니다. 대부분의 상황을 모델링하는 데 특히 좋은 방법이 아니기 때문에 저는 상속의 팬이 아닙니다. 어쨌든 계속해서 걱정하지 마십시오.

나는 이것이 대부분의 개발자들에게 괜찮다고 말하고 싶습니다 (그리고 아마도 그것에 대해 최선의 방법 일 것입니다).

문제의 간단한 사실은 다른 개발자가 1 년 후에 와서 개인 멤버 변수에 대한 액세스가 필요하다고 결정하면 코드를 편집하고 보호 된 것으로 변경하고 비즈니스를 계속할 것입니다.

이에 대한 유일한 예외는 바이너리 dll을 블랙 박스 형태로 제 3 자에게 배송하는 사업에있는 경우입니다. 이것은 기본적으로 Microsoft, 'Custom DataGrid Control'공급 업체 및 확장 성 라이브러리와 함께 제공되는 몇 가지 다른 대형 앱으로 구성됩니다. 당신이 그 범주에 속하지 않는 한, 이런 종류의 것에 대해 걱정하는 데 시간 / 노력을 소비 할 가치가 없습니다.


8

나에게 중요한 문제는 일단 변수를 보호 하면 하위 클래스가 항상 범위를 벗어날 수 있기 때문에 클래스의 어떤 메서드도 범위 내에있는 값에 의존 하도록 허용 할 수 없다는 것입니다.

예를 들어 렌더링 가능한 객체의 너비와 높이를 정의하는 클래스가 있고 해당 변수를 보호하는 경우 가로 세로 비율 (예 : 가로 세로 비율)에 대한 가정을 할 수 없습니다.

비판적으로 저는 코드가 라이브러리로 출시 된 순간부터 이러한 가정을 할 수 없습니다. 종횡비를 유지하기 위해 setter를 업데이트하더라도 변수가 setter를 통해 설정되거나 기존 코드의 게터.

내 클래스의 어떤 하위 클래스도 변수 값을 적용 할 수 없기 때문에 보장하도록 선택할 수 없습니다. 그 자신의 서브 클래스의 전체 지점의 경우에도 .

예로서:

  • 너비와 높이가 보호 된 변수로 저장되는 사각형 클래스가 있습니다.
  • 내 컨텍스트 내에서 명백한 하위 클래스는 "DisplayedRectangle"클래스입니다. 유일한 차이점은 그래픽 디스플레이에 대해 너비와 높이를 유효한 값으로 제한한다는 것입니다.
  • 하지만 지금은 불가능합니다. 내 DisplayedRectangle 클래스 가 해당 값을 진정으로 제한 할 수 없기 때문에 하위 클래스가 DisplayedRectangle로 처리되는 동안 값을 직접 재정의 할 수 있기 때문입니다.

변수를 비공개로 제한하면 setter 또는 getter를 통해 원하는 동작을 적용 할 수 있습니다.


7

일반적으로 보호 된 멤버 변수를 사용하는 코드를 완전히 제어 할 수있는 드문 경우로 유지합니다. 공용 API를 만드는 경우 절대로하지 않습니다. 아래에서 멤버 변수를 개체의 "속성"이라고합니다.

다음 은 private-with-accessor가 아닌 멤버 변수를 보호 한 후에 슈퍼 클래스가 할 수없는 작업입니다.

  1. 속성을 읽을 때 즉시 값을 느리게 만듭니다. 보호 된 getter 메서드를 추가하면 값을 느리게 생성하고 다시 전달할 수 있습니다.

  2. 속성이 수정되거나 삭제 된시기를 알 수 있습니다. 수퍼 클래스가 해당 변수의 상태에 대해 가정 할 때 버그가 발생할 수 있습니다. 변수에 대해 보호 된 setter 메서드를 만들면 해당 제어가 유지됩니다.

  3. 변수를 읽거나 쓸 때 중단 점을 설정하거나 디버그 출력을 추가합니다.

  4. 해당 멤버 변수를 사용할 수있는 모든 코드를 검색하지 않고 이름을 바꿉니다.

일반적으로 보호 된 멤버 변수를 만들 것을 권장하는 드문 경우라고 생각합니다. 몇 시간 후에 보호 된 변수를 수정 한 다른 코드에서 버그를 추적하는 것보다 게터 / 세터를 통해 속성을 노출하는 데 몇 분을 보내는 것이 좋습니다. 뿐만 아니라 종속 코드를 손상시키지 않고 향후 기능 (예 : 지연로드)을 추가하지 않도록 보장합니다. 지금하는 것보다 늦게하는 것이 더 어렵습니다.


7

디자인 수준에서는 보호 된 속성을 사용하는 것이 적절할 수 있지만 구현을 위해 접근 자 / 변이 자 메서드가 아닌 보호 된 멤버 변수에 매핑하는 이점이 없습니다.

보호 된 멤버 변수는 기본 클래스 클래스의 내부 상태에 대한 클라이언트 코드 (하위 클래스) 액세스를 효과적으로 허용하기 때문에 상당한 단점이 있습니다. 이것은 기본 클래스가 불변성을 효과적으로 유지하는 것을 방지합니다.

같은 이유로 보호 된 멤버 변수는 상수가 보장되거나 단일 스레드로 제한되지 않는 한 안전한 다중 스레드 코드 작성을 훨씬 더 어렵게 만듭니다.

접근 자 / 변이 자 메서드는 유지 관리 중에 훨씬 더 많은 API 안정성과 구현 유연성을 제공합니다.

또한 OO 순수 주의자라면 객체는 상태를 읽거나 설정하지 않고 메시지를 보내 공동 작업 / 통신합니다.

그 대가로 그들은 거의 장점을 제공하지 않습니다. 다른 사람의 코드에서 반드시 제거하지는 않지만 직접 사용하지는 않습니다.


4

대부분의 경우 protected를 사용하는 것은 잘못 설계된 파생 클래스에 의해 잘 분해 될 수있는 클래스의 캡슐화를 다소 깨뜨리기 때문에 위험합니다.

하지만 좋은 예가 하나 있습니다. 일종의 일반 컨테이너를 사용할 수 있다고 가정 해 보겠습니다. 내부 구현과 내부 접근자가 있습니다. 그러나 데이터에 대한 공개 액세스 권한을지도, hash_map, 벡터와 같이 3 개 이상 제공해야합니다. 그러면 다음과 같은 것이 있습니다.

template <typename T, typename TContainer>
class Base
{
   // etc.
   protected
   TContainer container ;
}

template <typename Key, typename T>
class DerivedMap     : public Base<T, std::map<Key, T> >      { /* etc. */ }

template <typename Key, typename T>
class DerivedHashMap : public Base<T, std::hash_map<Key, T> > { /* etc. */ }

template <typename T>
class DerivedVector  : public Base<T, std::vector<T> >        { /* etc. */ }

나는 이런 종류의 코드를 한 달 전에 사용했습니다 (따라서 코드는 메모리에서 가져온 것입니다). 몇 가지 생각을 한 후, 제네릭 Base 컨테이너는 추상 클래스 여야한다고 생각합니다. 비록 그것이 꽤 잘 살 수 있더라도 Base를 직접 사용하는 것은 매우 고통 스러울 것이기 때문에 금지되어야합니다.

요약 따라서 파생 클래스에서 사용하는 데이터를 보호했습니다. 그럼에도 불구하고 우리는 Base 클래스가 추상적이어야한다는 사실을 고려해야합니다.


공개 멤버보다 더 이상 캡슐화를 중단하지 않습니다. 파생 클래스가 클래스 사용자에게 노출되지 않은 클래스 상태를 사용할 수 있다는 설정입니다.
— gbjbaanb

@gbjbaanb : "퍼블릭 멤버가하는 것보다 더 이상 캡슐화를 중단하지 않습니다"가 "[유일한] 파생 클래스가 클래스의 상태를 사용할 수 있음"과 다르다는 사실이 모순됩니다. "protected"는 공개와 비공개의 중간입니다. 그래서 "보호 된 [...] 다소 캡슐화를 끊습니다"는 여전히 사실입니다 ...
— paercebal

실제로 C ++ 언어에서 std :: stack과 같은 컨테이너 어댑터는 "c"라는 보호 변수를 사용하여 기본 컨테이너 개체를 노출합니다.
— Johannes Schaub-litb

나는이 포스트가 꽤 오래되었다는 것을 알고있다. 그러나 나는 차임 할 필요성을 느낀다. 당신은 캡슐화를 "어느 정도"깨뜨리지 않고 완전히 깨뜨린 다. protected보다 더 이상 캡슐화되지 않습니다 public. 나는 기꺼이 틀렸다는 것을 증명할 것입니다. 당신이해야 할 일은 보호 된 멤버로 클래스를 작성하고 내가 그것을 수정하는 것을 금지하는 것입니다. protected 사용의 전체 요점은 상속을위한 것이기 때문에 클래스는 최종적이지 않아야합니다. 어떤 것이 캡슐화되어 있거나 그렇지 않습니다. 중간 상태가 없습니다.
— 태칸

3

요컨대, 그렇습니다.

보호 된 멤버 변수를 사용하면 동일한 패키지의 모든 클래스뿐 아니라 모든 하위 클래스에서 변수에 액세스 할 수 있습니다. 이것은 특히 읽기 전용 데이터에 매우 유용 할 수 있습니다. 그러나 보호 된 멤버 변수의 사용은 개인 멤버 변수와 몇 개의 getter 및 setter를 사용하여 복제 될 수 있기 때문에 이것이 필요하다고 생각하지 않습니다.


1
반대로 private 멤버 변수도 필요하지 않습니다. public은 모든 용도로 충분합니다.
— Alice

3

기록을 위해 "Exceptional C ++"의 항목 24 아래 각주 중 하나에서 Sutter는 "공개 또는 보호 된 멤버 변수가있는 클래스를 작성하지 않을 것입니다. 맞습니까? (일부 라이브러리에서 설정 한 좋지 않은 예제와 관계없이) .) "


2

.Net 액세스 수정 자에 대한 자세한 정보는 여기로 이동하십시오.

보호 된 멤버 변수에는 실제 장점이나 단점이 없으며 특정 상황에서 필요한 것이 무엇인지에 대한 질문입니다. 일반적으로 멤버 변수를 비공개로 선언하고 속성을 통해 외부 액세스를 활성화하는 것이 허용됩니다. 또한 일부 도구 (예 : 일부 O / R 매퍼)는 객체 데이터가 속성으로 표시 될 것으로 예상하고 공용 또는 보호 된 멤버 변수를 인식하지 못합니다. 그러나 서브 클래스 (및 서브 클래스 만)가 특정 변수에 액세스하기를 원한다는 것을 알고 있다면이를 보호 된 것으로 선언하지 않을 이유가 없습니다.


서브 클래스를 원하는 액세스 변수 것은 그들을 자유롭게 할 수 있도록하고자 매우 다른 변이 를. 이것이 보호 된 변수에 대한 주요 인수 중 하나입니다. 이제 기본 클래스는 모든 파생 클래스가 보호 된 멤버로 모든 작업을 수행 할 수 있기 때문에 불변성이 있다고 가정 할 수 없습니다. 그것이 그들에 대한 주요 논쟁입니다. 그들이 데이터 에 액세스 해야한다면 ... 접근 자를 작성하세요. : P (나는 보호 된 변수를 사용하지만 아마도 내가해야하는 것보다 더 많이 사용하고, 줄이려고 노력할 것입니다!)
— underscore_d
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.