깨지기 쉬운 베이스 클래스

Fragile base class

취약한 베이스 클래스 문제는 기본 클래스(슈퍼 클래스)가 "취약하다"고 간주되는 객체 지향 프로그래밍 시스템의 근본적인 구조적 문제로, 파생 클래스에 의해 상속되었을 때 베이스 클래스에 대한 겉보기에는 안전한 수정으로 인해 파생 클래스가 오작동할 수 있기 때문이다. 프로그래머는 기본 클래스의 방법을 분리하여 검토한다고 해서 기본 클래스 변경이 안전한지 판단할 수 없다.

한 가지 가능한 해결책은 인스턴스 변수를 정의 클래스에 전용으로 만들고 하위 클래스가 액세스자를 사용하여 슈퍼 클래스 상태를 수정하도록 하는 것이다. 언어는 또한 하위 계층이 어떤 유전적 방법이 공개적으로 노출되는지를 통제할 수 있도록 만들 수 있다. 이러한 변경은 하위 클래스가 슈퍼 클래스의 구현 세부사항에 의존하는 것을 방지하고 하위 클래스가 자신에게 적용되는 슈퍼 클래스 방법만 노출할 수 있도록 한다.

또 다른 대안 솔루션은 슈퍼클래스 대신 인터페이스를 갖는 것일 수 있다.

취약한 베이스 클래스 문제는 공개 재귀(dynamic dispatched of methods on.에 대한 동적 재귀)의 원인으로 지목되어 왔다. this))에 대한 방법을 호출하는 제안과 함께 this 공개 재귀가 아닌 폐쇄 재귀(정적 재귀, 조기 바인딩)로 기본 설정(특정 요청 시에만 공개 재귀 사용, 외부 통화(사용하지 않음) this)는 평상시처럼 동적으로 파견될 것이다.[1][2]

자바 예제

다음의 사소한 예는 Java 프로그래밍 언어로 쓰여져 있으며, 겉으로 보기에 안전한 것처럼 보이는 베이스 클래스의 수정으로 인해 스택 오버플로가 발생할 무한 재귀 입력으로 상속 하위 클래스가 오작동할 수 있는 방법을 보여준다.

계급 잘 하는 군요 {    사유의 인트로 반격하다 = 0;    공허하게 하다 inc1() {     반격하다++;   }    공허하게 하다 inc2() {     반격하다++;   }  }  계급 후보선수 연장하다 잘 하는 군요 {    @오버라이드   공허하게 하다 inc2() {     inc1();   }  } 

Sub 인스턴스에서 동적 바인딩 메서드 inc2()를 호출하면 필드 카운터가 1씩 올바르게 증가한다. 그러나 다음과 같은 방법으로 슈퍼클래스의 코드가 변경되는 경우:

계급 잘 하는 군요 {    사유의 인트로 반격하다 = 0;    공허하게 하다 inc1() {     inc2();   }    공허하게 하다 inc2() {     반격하다++;   } } 

Sub의 인스턴스에서 동적 바인딩 메서드 inc2()로 호출하면 자체와 수퍼 클래스의 메서드 inc1() 사이에 무한 재귀가 발생하고 결국 스택 오버플로가 발생한다. 이 문제는 슈퍼클래스의 방법을 최종으로 선언함으로써 피할 수 있었는데, 이는 서브클래스가 이를 무시하는 것을 불가능하게 만들 것이다. 그러나 이것이 항상 바람직하거나 가능한 것은 아니다. 따라서, 슈퍼클래스는 통화를 동적으로 바인딩된 방법으로 바꾸는 것을 피하는 것이 좋은 관행이다.

해결 방법

  • 목표-C에는 취약하지 않은 인스턴스(instance) 변수뿐만 아니라 범주가 있다.
  • 구성 요소 Pascal슈퍼클래스 통화를 부정한다.
  • Java, C++(C++11 이후) 및 D는 클래스 또는 메서드의 선언에 키워드를 각각 "로 표시하여 클래스 메서드를 상속하거나 재정의하는 것을 금지한다.final". 저자조슈아 Bloch효과적인 자바라는 책에서 (17번 항목에서) 프로그래머들은 "상속을 위해 설계하고 문서화하거나 아니면 금지해야 한다"고 쓰고 있다.
  • C#VB.Java와 같은 NET은 "를 가지고 있다.sealed" 그리고 "Not Inheritable"클래스 선언 키워드 " 상속을 금지하고 하위 클래스가 키워드를 사용하도록 요구함 "override스칼라가 채택한 해결책과 동일한 해결책이 있다.[3]
  • 스칼라는 키워드 "를 사용하기 위해 하위 클래스를 필요로 한다.override" 부모 클래스 메서드를 재정의하기 위해 명시적으로 ". 저자는 '스칼라에서의 프로그래밍, 제2판'이라는 책에서 (여기에 수정을 가한 채) 메서드 f()가 없었다면 클라이언트의 원래 메서드 f() 구현에 오버라이드 수식어가 있었을 리 없다고 쓰고 있다. 라이브러리 클래스의 두 번째 버전에 f() 메소드를 추가하면 클라이언트 코드의 재컴파일에서 잘못된 동작 대신 컴파일 오류가 발생한다.
  • Kotlin에서 클래스와 방법은 기본적으로 최종이다. 클래스 상속을 사용하려면 클래스에 다음이 표시되어야 한다. open 수식어 마찬가지로, 방법은 다음과 같이 표시되어야 한다. open 방법의 우선권을 허용하다
  • Julia는 추상적인 유형의 하위 형식만 허용하고 유산의 대안으로 구성을 사용한다. 그러나 그것은 다중 파견이다.

참고 항목

참조

외부 링크

  • Mikhajlov, Leonid; Sekerinski, Emil (1998). "A Study of The Fragile Base Class Problem" (PDF). ECOOP’98 — Object-Oriented Programming. ECOOP 1998. LCNS. Vol. 1445. pp. 355–382. doi:10.1007/BFb0054099. ISSN 0302-9743. QID 29543920. Retrieved 2020-07-21.
  • Holub, Allen (August 1, 2003). "Why extends is evil". Java Toolbox. JavaWorld. Retrieved 2020-07-21.