2011-01-12 6 views
8
다음

나를 귀찮게 코드의 샘플입니다파생 클래스에서 기본 클래스의 보호 된 메서드에 액세스하는 방법?

class Base { 
    protected: 
    virtual void foo() = 0; 
}; 

class Derived : public Base { 
    private: 
    Base *b; /* Initialized by constructor, not shown here 
       Intended to store a pointer on an instance of any derived class of Base */ 

    protected: 
    virtual void foo() { /* Some implementation */ }; 
    virtual void foo2() { 
     this->b->foo(); /* Compilator sets an error: 'virtual void Base::foo() is protected' */ 
    } 
}; 

당신이 보호 오버라이드 기능에 어떻게 액세스합니까?

도움 주셔서 감사합니다. : o)

+7

귀하의 구현이 옳다고 생각하지 않습니다. 왜 멤버 변수로 Base 인스턴스가 있습니까? this-> b-> foo()는 순수 가상 메서드를 호출하려고합니다. – GWW

+1

이 프로그램을 컴파일해서는 안됩니다. 추상 클래스를 인스턴스화 할 수 없습니다 ....'b'가'Base'에서 파생 된 다른 클래스의 인스턴스를 가리키지 않으면. – 341008

+0

정밀도가 생략되었습니다. Derived :: b 특성은 기본 –

답변

8

기본 클래스의 보호 된 멤버는 현재 개체에서만 액세스 할 수 있습니다.
따라서 this->foo()에 전화 할 수는 있지만 this->b->foo()으로 전화 할 수는 없습니다. 이것은 Derivedfoo에 대한 구현을 제공하는지 여부와 관계없이 독립적입니다.

이 제한 사항의 이유는 보호 된 액세스를 피하는 것이 매우 쉽기 때문입니다. Derived과 같은 클래스를 만들면 갑자기 외부인이 액세스 할 수없는 다른 클래스 (예 : OtherDerived)에 액세스 할 수 있습니다.

+0

감사합니다. 이제 제한 이유를 분명히 이해합니다. 보안 구멍이 될 것입니다. 큰 것입니다! –

+5

보안 구멍으로 생각하지 마십시오. 액세스 한정자는 보안을 제공하지 않으므로 데이터를 원한다면 메모리 위치를 읽을 수 있습니다. – DrYap

5

일반적으로 현재 인스턴스의 기본 클래스를 나타내는 Base::foo()을 사용하면됩니다.

그러나 코드가 시도하는 방식대로해야하고 허용되지 않으면 foo()를 공개하거나 Derived를 Base의 친구로 만들어야합니다.

0

범위 연산자 (Base :: foo())를 사용하여 명시 적으로 기본 함수를 호출합니다. 하지만이 경우 기본 클래스는 foo (순수 가상)를 정의하지 않으므로 this->b->foo();이라고 할 때 실제로 실행할 함수가 없습니다. b는 Base에 대한 포인터이고 Derived가 아니기 때문입니다.

+1

에서 파생 된 클래스의 인스턴스를 저장하기위한 것이지만 OP 코드는 현재 인스턴스의 기본 클래스를 참조하지 않습니다. 그는 다른 인스턴스에 액세스하고 있는데, 아마도 순수 가상 함수를 구현하는 파생 클래스입니다. (그렇지 않으면 인스턴스를 만들 수 없습니다.) –

+0

@Jonathan Wood 당신이 말한 것을 이해하지만 그가 게시 한 코드를 살펴보면 추상 기본 클래스 (Base)를 인스턴스화하고 순수한 가상 함수 (Base :: foo())는 no-no (GWW와 위에서 언급 한 341008)입니다. – Gemini14

0

보호 된 무시 된 기능에 어떻게 액세스합니까?

--- 어디에서?

상속을 통해서만 (동일한 클래스의 메소드 제외) 보호 된 멤버에 액세스 할 수 있습니다. 예를 들어 이 Derived에서 상속 된 경우 Derived1의 객체는 foo()으로 전화 할 수 있습니다.

보호 액세스 지정자에 대한 편집 : MSDN article

1

다소 약하지만, 여기서 정의한 클래스를 사용하면 작동하지 않습니까?

virtual void foo2() { 
    reinterpret_cast<Derived *>(this->b)->foo(); 
} 

reinterpret_cast는 기본 객체의 VTABLE을 가리키며이 구성원 접근자를 통해 호출합니다.

2

하나의 해결책은 호를 개인/보호 기능 (예제에서는 foo)으로 리디렉션하는 Base에 정적으로 보호 된 기능을 선언하는 것입니다.

class Base { 
protected: 
    static void call_foo(Base* base) { base->foo(); } 
private: 
    virtual void foo() = 0; 
}; 

class Derived : public Base { 
private: 
    Base* b; 
protected: 
    virtual void foo(){/* Some implementation */}; 
    virtual void foo2() 
    { 
     // b->foo(); // doesn't work 
     call_foo(b); // works 
    } 
}; 

이 방법은, 우리가 캡슐화를 중단하지 않는 foo을 넣어 피하면서 Base의 디자이너, 명시 적 선택은 모든 파생 클래스가 서로 foo를 호출 할 수 있도록 만들 수 있기 때문에 :

말할 수 있습니다 공개 인터페이스에 삽입하거나 명시 적으로 Base의 가능한 모든 하위 클래스를 친구로 바꿀 수 있습니다.

또한이 방법은 foo이 가상인지 여부와 관계없이 또는 개인 또는 보호되어 있는지 여부에 관계없이 작동합니다.

Here은 위의 코드의 실행 버전에 대한 링크이고 here 조금 더 비즈니스 로직이있는 동일한 아이디어의 다른 버전입니다.

관련 문제