2011-08-04 1 views
2

이것은 성능에 대해 너무 걱정하지 않는다는 점에서 약간의 가설입니다. 실제로 어떤 옵션이 실제로 가장 빠르고/가장 효율적인지 궁금하거나, 차이가 전혀 없는지 궁금합니다.더 빠른 방법 : 가상 기반이나 크로스 캐스트를 사용하여 다운 캐스트 할 수 있습니까?

가정하자 나는 방문자 템플릿 다음 코드 오버로드를 지원 한 것을 : 방문자가 궁극적으로 dynamic_cast<> 's의 결과 사용

class CommonBase { 
    IMPLEMENT_VISITOR_WITH_SUPERCLASS(void) 
    virtual ~CommonBase() = 0; 
}; 
class A : public CommonBase { 
    IMPLEMENT_VISITOR_WITH_SUPERCLASS(CommonBase) 
}; 
class B : public CommonBase { 
    IMPLEMENT_VISITOR_WITH_SUPERCLASS(CommonBase) 
}; 

class MyVisitor 
    : public Visitor 
    , public VTarget<CommonBase> 
    , public VTarget<A> 
    , public VTarget<B> 
{ 
public: 
    virtual void dispatch(CommonBase& obj); 
    virtual void dispatch(A& obj); 
    virtual void dispatch(B& obj); 
}; 

:

#define IMPLEMENT_VISITOR_WITH_SUPERCLASS(superclass) \ 
    typedef superclass visitor_super_t;  \ 
    virtual void visit(Visitor& v) { v.visit(*this); } 
//----------------------------------------------------------------------------- 
// Implementation detail: 
// Selective dispatcher for the visitor - required to handle overloading. 
// 
template <typename T> 
struct VisitorDispatch { 
    static void dispatch(Visitor* v, T* t) { v->visit(*t); } 
}; 
// Specalization for cases where dispatch is not defined 
template <> struct VisitorDispatch<void> { 
    static void dispatch(Visitor* v, void* t) { throw std::bad_cast(""); } 
}; 

//----------------------------------------------------------------------------- 
// Derive visitors from this and 'Visitor'. 
template <typename T> 
class VTarget 
{ 
public: 
    // Don't really need a virtual dtor. 
    virtual void dispatch(T& t) = 0; 
}; 

//----------------------------------------------------------------------------- 
class Visitor 
{ 
public: 
    virtual ~Visitor() = 0; 

    template <typename T> 
    void visit(T& t) { 
     typedef VTarget<T> target_t; 
     target_t* tgt = dynamic_cast<target_t*>(this); 
     if (tgt) { 
      tgt->dispatch(t); 
     } 
     else { 
      // Navigate up inhertiance hierarchy. 
      // requires 'super' to be defined in all classes in hierarchy 
      // applicable to this visitor. 
      typedef typename T::visitor_super_t super; 
      super* s = static_cast<super*>(&t); 
      VisitorDispatch<super>::dispatch(this, s); 
     } 
    } 
}; 

//----------------------------------------------------------------------------- 
inline Visitor::~Visitor() {} 

이 다음 일반 방문자를 만드는 데 사용됩니다 Visitor에서 VTarget<T>까지이며, 이것은 크로스 캐스트입니다.

VTarget<T>-의 가상베이스를 방문자가 더 이상 직접 상속하지 않아도되도록 구현할 수 있습니다. Visitor :: visit 코드의 dynamic_cast<>은 가상베이스에서 다운 캐스트가 발생합니다 (Visitor).

캐스트를 수행 할 때 한 방법이 다른 방법보다 빠릅니까? 또는 가상 기반을 가지고있는 경우에만 크기 패널티가 있습니까?

+3

"캐스트를 수행 할 때 다른 방법보다 한 가지 방법이 더 빠릅니까?" 이에 대한 유일한 현명한 방법은 실제로 측정하는 것입니다. 그 코드는 코드에 따라 다르므로 행운을 빈다. 투표를 종료합니다. –

+2

또한, 방문자의 모든 지점은 캐스팅이 필요 없다는 것입니다. –

+0

@Alexandre이 방문자가 이런 식으로 구현 된 이유는 클래스 계층의 방문자 대상에 대한 종속성이 없다는 것입니다. 그런 식으로 클래스 계층 구조의 일부는 라이브러리 및 클라이언트 코드의 다른 부분에 상주 할 수 있습니다. 이는 기존의 정적 인 방문자가 실제로는 불가능합니다. – Pete

답변

1

글쎄, 크로스 캐스트 방법이 가상 기본 방법보다 빠릅니다.

수퍼 클래스로 1 회 폴백, 100000000 회 반복, 크로스 캐스트 방법이 30.2747 초, 가상 기본 방법이 41.3999 - 약 37 % 느려졌습니다.

수퍼 클래스의 오버로드에 대한 대체 기능이 없으면 크로스 캐스팅은 10.733 초였으며 가상베이스는 19.9982 (86 % 느림)였습니다.

dynamic_cast가 두 모드에서 모두 어떻게 작동하는지 알고 싶습니다.

+0

공유 라이브러리 (.dll 또는 .so)의 방문자 코드와 주 프로그램의 클라이언트 코드로 동일한 코드를 사용해 보셨습니까? 내 생각은 그것이 일을 많이 바꾼다는 것이다.또한 계층 구조에서 클래스의 수를 늘려 확장 성을 확인하십시오. 방문 가능한 클래스 당 방문자 클래스에 추가 포인터가 있음을 기억하십시오. –

+0

이것은 간단한 콘솔 앱에 존재하지 않습니다. 매우 강력하지 않기 때문에 일반적으로 공유 라이브러리에 대해서는 dynamic_cast를 사용하지 않는 것이 좋습니다. 나는 그것이 상당히 느릴 것이라고 예상한다. 아마도 두 가지 방법 사이의 성능 차이는 아마 적을 것이다. – Pete

관련 문제