2010-06-15 7 views
5

클래스에서 'this'포인터를 인터페이스 중 하나의 포인터로 변환 할 수 없도록하려고합니다. 중간 프록시 클래스를 통해 개인 상속을 사용하여이 작업을 수행합니다. 문제는 내가 개인 상속을 발견하면 모든 공용 정적 멤버와 기본 클래스의 유형이 계층의 상속 클래스 아래에있는 모든 클래스에 액세스 할 수 없게됩니다.C++ 개인 상속 및 정적 멤버/형식

class Base 
{ 
public: 
    enum Enum 
    { 
     value 
    }; 
}; 

class Middle : private Base 
{ 
}; 

class Child : public Middle 
{ 
public: 
    void Method() 
    { 
     Base::Enum e = Base::value; // doesn't compile BAD!  
     Base* base = this; // doesn't compile GOOD! 
    } 
}; 

둘 다 VS2008 (필요한 버전) 및 VS2010, 어느 작업이 시도했습니다.

해결 방법은 누구나 생각할 수 있습니까? 또는 전환을 중지하는 다른 방법은 무엇입니까?

또한 나는이 동작의 골자를 쓰고 있는데, 이것은 컴파일러 구현의 부작용입니까, 아니면 의도적으로 설계된 것입니까? 설계 상으로는 그렇다면 왜 그렇습니까? 나는 항상 개인이 상속으로 생각하여 미들이 기지에서 물려 받았다는 것을 아무도 모른다는 것을 의미합니다. 그러나 전시 된 행동은 사적 상속이 그 이상을 의미한다는 것을 의미합니다. 실제로 클래스 계층 구조가 아닌 모든 네임 스페이스보다 Base에 대한 액세스 권한이 적습니다.

+0

+1 : 정말 흥미로운 질문입니다. –

답변

6

당신은 완전히 자격으로 Base::Enum에 액세스 할 수 있어야는 :

참고 :

class Child : public Middle 
{ 
public: 
    void Method() 
    { 
     ::Base::Enum e = ::Base::value; 
    } 
}; 

이 언어 (C++ 03 §11.2/3)에 의해 지정된 동작입니다 : 개인 기본 클래스의 멤버는 상속 된 멤버 이름으로 액세스 할 수 없지만 직접 액세스 할 수 있습니다.

다음은 예제 코드와 매우 유사한 확장 예제입니다.

그러나 Visual C++ 2008도 Visual C++ 2010도 올바르게 구현되어 있지 않으므로 ::Base::Enum 유형을 사용할 수 있지만 여전히 ::Base::value에 액세스 할 수는 없습니다. (사실, Visual C++은 잘못 입력 된 것 같습니다. 정확히 말하면 정규화되지 않은 Base::Enum을 사용할 수 있기 때문입니다.)

문제는, 당신은 Middle 클래스 선언을 사용하여 추가 할 수 있습니다 "주위를 얻을"다음

class Middle : private Base 
{ 
protected: 

    using Base::Enum; 
    using Base::value; 
}; 

이것은 당신이 당신의 Child 클래스 Base::Enum 또는 Base::value을 사용하지 않습니다,하지만 당신을 수 Enumvalue 또는 Middle::EnumMiddle::value을 사용하십시오.

+1

Visual C++ 버그에 관한 Microsoft Connect의 버그 보고서를 제출했습니다. https://connect.microsoft.com/VisualStudio/feedback/details/567693/ –

+0

자세한 답변을 보내 주셔서 감사합니다. 짜증나는 것은 버그로 인한 것입니다. 불행히도 중간 클래스를 사용하는 것은 실세계의 경우 옵션이 아닙니다. 중간 클래스는 기본 클래스를 Type 인수로 취하는 템플릿 클래스입니다. 내 유일한 옵션은 인터페이스 외부에서 열거 형을 이동하는 것입니다. – WearyMonkey

+0

내가 인용 한 표준의 "메모"는 실제로 아무것도 지정하지 않고 단지이 동작을 설명합니다. 내 생각에이 동작의 실제 사양은 이름 확인이 이루어지는 방식을 설명하는 다양한 섹션을 통해 확산됩니다. –

1

나는 한 가지 질문 만 가지고 있습니다. 왜 당신은 상속을 전혀하지 않습니까? 당신이

  • 당신이
  • 불행히도 상속이 필요 구현을 상속 인터페이스를 상속

    • : 그것은 하나 책임의 원칙을 위반

      상속, 내 의견으로는, 꽤 깨진 개념이다 객체 지향 코드에서의 다형성을 위해,이 경우에 당신은 그것을 멀리 부끄럽게 생각할 수 없다.

      하지만 여기에서는 다형성을 사용하지 않기를 바라고 있기 때문에 상속을 전혀 사용하지 않는 이유가 궁금합니다. 왜냐하면 그것은 유일한 흥미로운 용도이기 때문입니다.

      대신, C++, 당신은 사용할 수 있습니다

      • 조성, 코드 재사용을 위해 (자신의 네임 스페이스에 정의)
      • 무료 기능
      • using, typedef 등 ...에서 개체를 가져 클래스 외부

      당신의 예제는 여기에 제한된 것처럼 보입니다.하지만 역시 열거 형을 struct으로 감싸서 (그리고 네임 스페이스가 가질 수없는 템플릿 매개 변수로 struct을 사용할 수 있기 때문에).

      struct MyEnum 
      { 
          enum type 
          { 
          value 
          }; 
      }; 
      
      class Child 
      { 
      public: 
          typedef MyEnum::type Enum; 
      
          Child(Enum e = MyEnum::value); 
      
      private: 
      }; 
      
      내가 대신 나는 당신이 우리가 얘기하는 열거 알고 있기 때문에, 다시 읽기 쉬워하게 느낄 이름을 자격과 아무 잘못 표시되지 않습니다

      ...

      정말, private 상속 가장 피해야합니다 (일반적으로 작문으로 대체됩니다). 유일한 유효 케이스 (imo)는 Empty Base Optimization을위한 것입니다. 솔직히 말해서 (자주 최적화 할 때처럼) 자주 필요하지 않습니다.

    +0

    개인 상속의 또 다른 용도는 클래스의 보호 된 멤버에 대한 액세스가 필요한 경우입니다. 그것은 이상적인 상황은 아니지만 드문 경우입니다. 나는 그것이 최고의 피할 것을 동의합니다. –

    +0

    나는 보통이 시점에서 디커플링하는 것을 선호한다. 나는 공개적으로 상속 받고 컴포지션을 사용하는 중급 클래스를 만든다. –

    +0

    필자는 가능하다면 구성이 상속보다 바람직하다는 것에 확실히 동의한다. 그러나 실제 문제의 기본 클래스는 오래된 대규모 코드베이스의 핵심 클래스이므로 적절한 리팩터 작업을 수행하면 대부분의 코드를 다시 작성해야합니다. – WearyMonkey