동적 디스패치 (다형성)가 없으면 "메소드"는 단순한 함수일 뿐이며 암시적인 추가 매개 변수가있을 수 있습니다. 따라서, 다형성 거동이없는 클래스의 인스턴스는 본질적 struct
으로 코드 생성을위한 C 이다.
정적 유형 시스템의 클래식 동적 디스패치에는 기본적으로 하나의 주요 전략 인 vtables가 있습니다. 모든 인스턴스는 유형, 가장 중요한 vtable을 나타내는 (한정된 표현) 추가 포인터 하나 를 얻습니다 . 메소드 당 하나의 함수 포인터 배열. 모든 유형에 대한 전체 메소드 세트 (상속 체인에서)는 컴파일 타임에 알려져 있으므로, 메소드에 연속 인덱스 (N 메소드의 경우 0..N)를 지정하고 함수 포인터를 찾아 메소드를 호출 할 수 있습니다. 이 인덱스를 사용하는 vtable (인스턴스 참조를 추가 매개 변수로 전달 함)
보다 동적 인 클래스 기반 언어의 경우 일반적으로 클래스 자체는 일류 객체이며 각 객체는 대신 해당 클래스 객체에 대한 참조를 갖습니다. 클래스 객체는 언어에 의존하는 방식으로 메소드를 소유합니다 (루비에서 메소드는 객체 모델의 핵심 부분입니다. 파이썬에서는 작은 래퍼가있는 함수 객체 일뿐입니다). 클래스는 일반적으로 수퍼 클래스에 대한 참조도 저장하고, 메소드를 추가하고 변경하는 메타 프로그래밍을 돕기 위해 상속 된 메소드 검색을 해당 클래스에 위임합니다.
클래스를 기반으로하지 않는 다른 많은 시스템이 있지만 크게 다르므로 흥미로운 디자인 대안 중 하나만 선택합니다. 프로그램의 어느 곳에서나 모든 유형에 새로운 (세트) 메소드를 추가 할 수있는 경우 ( 예를 들어 Haskell의 유형 클래스와 Rust의 특성), 컴파일하는 동안 전체 메소드 세트를 알 수 없습니다. 이를 해결하기 위해 특성 당 vtable을 생성 하고 특성 구현이 필요할 때 전달합니다. 즉, 다음과 같은 코드입니다.
void needs_a_trait(SomeTrait &x) { x.method2(1); }
ConcreteType x = ...;
needs_a_trait(x);
이 컴파일됩니다 :
functionpointer SomeTrait_ConcreteType_vtable[] = { &method1, &method2, ... };
void needs_a_trait(void *x, functionpointer vtable[]) { vtable[1](x, 1); }
ConcreteType x = ...;
needs_a_trait(x, SomeTrait_ConcreteType_vtable);
이것은 vtable 정보가 객체에 포함되지 않았 음을 의미합니다. 예를 들어, 다양한 유형을 포함하는 데이터 구조에 저장 될 때 올바르게 작동하는 "특성 인스턴스"에 대한 참조를 원하면 팻 포인터를 작성할 수 있습니다 (instance_pointer, trait_vtable)
. 이것은 실제로 위 전략의 일반화입니다.