2008-09-29 4 views

답변

19

Simulated dynamic binding. 계층 적 이점 중 일부를 유지하면서 가상 함수 호출의 비용을 피하는 것은 현재 작업중인 프로젝트에서 수행 할 수있는 하위 시스템에 큰 도움이됩니다.

+0

어떤 종류의 성능 및/또는 메모리 사용 효과가 발생합니까? 얻을, btw? –

+0

계산량 감소에 소요 된 시간을 한 자리수로 보았습니다. 이것은, 틀림없이 아주 희귀 한 모서리의 경우였으며 대개 덜 극적이었습니다. 메모리 사용량 증가는 전체적인 메모리 사용량 중 무시할만한 비율입니다. – moonshadow

+1

어떻게 사용할 수 있는지 알 수 없습니다. Polymorhpishm은 기본 클래스 포인터를 사용하여 파생 클래스의 유형에 따라 파생 클래스 메서드를 호출하여 작동합니다. 그러나 CRTP 코드에서 당신은 여전히 ​​ 템플릿에있는 <유형 이름 유래> 클래스베이스 { 공개 : 무효 IMPL() { static_cast (이) -> IMPL(); } }; 파생 클래스 : public base < derived > { void impl() { /* something */ } }}; 베이스 < derived *> basePtr; 템플릿의 파생 클래스를 언급해야했습니다.이 파생 클래스는 파생 클래스 – ScaryAardvark

1

일반적으로 컴파일 타임에만 파생 클래스를 런타임에서 선택할 필요가없는 다형성 패턴에 사용됩니다. 이렇게하면 런타임에 가상 함수 호출의 오버 헤드를 줄일 수 있습니다.

+0

@Greg : 코드 예제를 줄 수 있습니까? before : [[클래스 B {가상 void f() = 0; void g() {.. f(); 클래스 D : B (공백 g() {static_cast (this) -> f();}}); 클래스 D : B {void f();} {void f();};]] 등등. – Aaron

-1

C 매크로와 비슷합니다. 매크로는 정의 시점이 아니라 사용 시점에 컴파일됩니다.

#define CALL_THE_RIGHT_FOO foo() 

파일 A :

static void foo() { 
    // do file A thing 
} 
... 
CALL_THE_RIGHT_FOO 
... 

파일 A :

당신이 설명하고 템플릿의 사용 패턴은 우리가 연기, 할 부모 템플릿의 "권리 foo에 전화를"수
static void foo() { 
    // do file B thing 
} 
... 
CALL_THE_RIGHT_FOO 
... 

template이 인스턴스화 될 때까지 정확히 foo가 무엇인지에 대한 정의. 이 경우를 제외하고는 ClassA :: foo와 ClassB :: foo의 구분이 Parent의 T 값을 기반으로합니다.

19

mixins (기능을 제공하기 위해 상속받은 클래스를 의미 함) 자체가 어떤 유형의 작업을하는지 (템플릿이 필요함) 알아야 할 경우 특히 유용합니다.

효과적인 C++에서 스콧 마이어스는 예를 들어 클래스 템플릿 NewHandlerSupport <T>을 제공합니다. 여기에는 특정 클래스에 대한 새 처리기를 재정의하는 정적 메서드가 포함되어 있습니다 (new 연산자에 대해 std :: set_new_handler가 수행하는 것과 같은 방식으로). 처리기 new를 사용하는 new 연산자. per-type 핸들러를 제공하기 위해, 부모 클래스는 그것이 어떤 타입인지를 알아야하기 때문에 클래스 템플릿이어야합니다. 템플릿 매개 변수는 하위 클래스입니다.

NewHandlerSupport 템플릿을 별도로 인스턴스화해야하기 때문에 CRTP없이이 작업을 수행 할 수 없습니다.이 템플릿을 사용하는 클래스별로 현재 new_handler를 저장하는 별도의 정적 데이터 멤버가 필요합니다.

분명히 전체 예제는 스레드 안전성이 매우 뛰어나지 만 요점을 보여줍니다.

마이어스는 CRTP가 "Do It For Me"라고 생각할 수 있다고 제안합니다. 나는 이것이 일반적으로 모든 mixin의 경우라고 말하고, mixin 클래스가 아닌 mixin 템플릿이 필요한 경우 CRTP가 적용됩니다.

4

수퍼 클래스에 전달 된 하위 클래스 유형이 메서드 확장시에만 필요하다고 생각하면 CRTP의 관심이 훨씬 줄어 듭니다. 그러면 모든 유형이 정의됩니다. 기호 하위 클래스 유형을 수퍼 클래스로 가져 오는 패턴 만 있으면되지만, 모든 공식 템플릿 매개 변수 유형은 정의에 따라 - 수퍼 클래스와 관련하여 정방향 선언 일뿐입니다.

우리는 다소 변형 된 형태로 특성 유형 구조의 서브 클래스를 수퍼 클래스로 전달하여 수퍼 클래스가 파생 된 유형의 객체를 반환 할 수있게합니다. 응용 프로그램은 모든 일반 기능이 수퍼 클래스에서 구현되는 기하학 미적분학 (점, 벡터, 선, 상자)을위한 라이브러리이며 하위 클래스는 특정 유형을 정의합니다. CFltPoint는 TGenPoint에서 상속합니다. 또한 CFltPoint는 TGenPoint 이전에 존재했기 때문에 하위 클래스 화는 자연스러운 리팩터링 방법이었습니다.

+0

@QBizZ : 가상 함수를 통해 구현 될 수 있다는 사실을 알고 있습니까? 기본 클래스에 대한 포인터를 반환하는 가상 함수는 파생 클래스 내에서 파생 클래스에 대한 포인터를 반환 할 수 있습니다. –

+0

공동 변형 반환 유형에 대해 이야기하고 있습니까? 가상 메소드 오버라이드가 기본 클래스의 원래 반환 유형에서 파생 된 클래스에 대한 포인터 (또는 참조)를 반환 할 수있는 곳은 어디입니까? 그렇다면이 사실을 알고 있습니다. 하지만 기본 클래스에 대한 계약이 인터페이스에 의해 정의 된 이후로 나에게 그것은 다른 것입니다. 기본 클래스가 액세스 할 수있는 메소드 (또는 다른 식별자)가 없기 때문에 일부 정의에서는 볼 수 없습니다. CRTP에서 기본 클래스는 호출 시점에 정의되지 않은 하위 클래스의 메서드를 호출 할 수 있습니다. 이것은 인스턴스화 시점에서 발생합니다. – QBziZ

1

실제 라이브러리에서 CRTP를 사용하려면 ATL 및 WTL (wtl.sf.net)을 참조하십시오. 컴파일 타임 다형성을 위해 광범위하게 사용됩니다.