2011-08-04 83 views
2

這是有點假設的,因爲我並不太擔心性能 - 只是想知道哪種選項實際上是最快/最有效的,或者如果沒有任何區別。速度更快:從虛擬基地還是十字路口向下投射?

假設我有一個訪問者模板下面的代碼,支持超載:

#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() {} 

這然後用於創建通用的用戶:

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); 
}; 

利用訪問者最終導致dynamic_cast<>的從VisitorVTarget<T>,這是一個十字路口。

可以實現的另一種方式是使Visitor成爲虛擬基礎VTarget<T> - MyVisitor不需要直接從Visitor繼承。 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

相關問題