자식은 부모의 보호된 맴버에 접근할 수 없습니다.

Sharlotte ·2023년 11월 14일
0

자식은 부모의 보호된 맴버에 접근할 수 있습니다.

사실 아닙니다.


Java, C#, TypeScript 이 세가지 언어에서 동일하게 구현된 코드들은 동일한 케이스에서 유사한 에러를 발생시킵니다.

일반적으로, 자식 클래스에선 부모 클래스의 protected맴버에 접근할 수 있습니다. 그러나 이는 상반된 결과를 내포하는 생략이 들어간 말입니다.
자식 클래스에선 부모 클래스의 자신protected맴버에 접근할 수 있지만, 부모 클래스의 다른 인스턴스protected맴버에 접근할 수 없습니다.

MSDN에 따르면 protected의 의미

protected - Access is limited to the containing class or types derived from the containing class.

이므로 "어느 한 클래스에서 자신 또는 파생 클래스의 protected맴버에 접근할 수 있다" 라는 원칙으로 정리할 수 있습니다.

즉, 부모 클래스의 다른 인스턴스protected맴버에 접근할 수 없는건 두가지 관점에서 해석될 수 있습니다.

  • 타입의 관점에서: 인스턴스의 형식이 자신 또는 파생의 형식이 아니므로 protected로 보호되어 접근할 수 없습니다.
  • 안전성의 관점에서: 런타임에 이 인스턴스가 자신 또는 파생의 인스턴스인지 아닌지가 불확실하므로 컴파일러가 사전에 차단합니다.

따라서 자식 클래스에서 부모 클래스 타입의 protected맴버에 접근하고 에러를 맞이하는 것은 근본적으로 위 원칙에 해당하지 않았지만 그렇게 되길 기대하는 개발자의 오인으로 인해 생긴 문제이므로 위 원칙에 해당되도록 타입 캐스팅을 하면 됩니다.

class Super
{
    protected float prot;
    private float priv;
}

class Sub2 : Super
{
    public void SubMethod(Sub1 sub1, Sub2 sub2, Super super)
    {
     	// NOT error, because of private access's limitation
        Debug.Log(sub2.prot);
        
        // error, because of private access's limitation
        Debug.Log(super.priv);
        
        // error, not because of protected access's limitation, but because of type of a qualifier 
        Debug.Log(super.prot); 
        
        // because the error is not because of protected access, can be solved via upcasting
        Debug.Log(((Sub2) super).prot); 
    }
}


흥미로운 점은 이것이 protected뿐만이 아니라 private에도 해당된다는 것입니다.
따라서 이 케이스가 유의미한 점은 접근 제한자를 단순히 "자신, 자식, 패키지(네임스페이스), 전역"으로 사분등하는 일반적인 이해의 허점을 찌른다는 것입니다. 즉, 이 일반적인 이해에선 "자신"과 "자식"을 "자신(의 인스턴스)", "자식(의 인스턴스)"로 생략하지만, 접근을 하는 장소인 클래스에도 해당이 된다는 뜻입니다. 이 케이스를 공유했을 때, 경험 많은 개발자들은 이를 알고 있거나 논리적으로 추측했지만 초보자들은 이에 당황했습니다.
이 일반적인 이해로 교육하는 것에 정면으로 비판하는게 아닙니다 - 다만 접근 제한자를 생각할 때 추가로 클래스까지 고려된다는걸 알려줘야 한다는 것입니다. (언젠가 밟게 될 억까 지뢰를 피하기 위해서라도)

실용적으로 보았을 때: 이 케이스로 얻을 교훈은 "자식 클래스에서 다른 부모 인스턴스의 보호된 맴버에 접근할 수 없다" 입니다. 우리가 늘 써온 super.memberbase.member 따위의 코드들은 다른 부모 인스턴스가 아니라 바로 자기 자신이 부모 클래스에 접근하기 위한 키워드들입니다.

side note: this를 upcast한다면?

만약 this 키워드를 부모 클래스로 형변환다면 놀랍게도 컴파일러는 "같은 부모 인스턴스"가 아니라 "다른 부모 인스턴스"로 인식하는 것인지 에러를 일으킵니다.

뇌피셜이지만 이것이 바로 super, base 키워드가 그저 syntax sugar가 아니라는 것의 증거지 않을까 싶습니다.

profile
샤르르르

0개의 댓글