Double Dispatch(雙分派)(c++ 版)

參考文獻地址: http://gurudk.iteye.com/blog/322753 測試

分派過程就是肯定一個方法調用的過程,雙分派就是根據運行時多個對象的類型肯定方法調用的過程。 this

想象這樣一個客戶服務的場景,通常客戶支持有一級支持和二級支持。一級支持通常解決比較簡單的問題,若是問題解決不了,就會由二級支持來解決。 spa

定義通常問題: 3d

class Problem
{
public:
     Problem(){}
     virtual ~Problem(){} 
};

定義特殊問題: 調試

class SpecialProblem:public Problem
{
public:
     SpecialProblem(){}
     ~SpecialProblem(){}
};

定義一級支持: code

class Supporter
{
public:
     Supporter(){}
     virtual ~Supporter(){}

     virtual void solve(Problem &p)
     {
          std::cout<<"一級支持解決通常問題"<<std::endl;
     }
     virtual void solve(SpecialProblem &sp)
     {
          std::cout<<"一級支持解決特殊問題"<<std::endl;
     }
};

定義資深支持: 對象

class SeniorSupporter:public Supporter
{
public:
     SeniorSupporter(){}
     ~SeniorSupporter(){}

     void solve(Problem &p)
     {
          std::cout<<"資深支持解決通常問題"<<std::endl;
     }
     void solve(SpecialProblem &sp)
     {
          std::cout<<"資深支持解決特殊問題"<<std::endl;
     }
};

下面是測試類: blog

int main()
{
     Problem *p=new Problem();
     Problem *sp=new SpecialProblem();
     Supporter *s=new SeniorSupporter();

     s->solve(*p);
     s->solve(*sp);

     system("Pause");
     return 1;
}

如下是預料中的錯誤運行結果: 接口

 

反彙編代碼以下:
 
 
若是本身動手編寫相似的程序並設置斷點調試的話就會發現:
s->solve(*p); 
s->solve(*sp);
調用的都是void SeniorSupporter::solve(Problem &p){...}這個方法。
緣由很簡單:C++不支持Double Dispatch。但C++支持single Dispatch(單分派),在單分派語言中,到底由哪種操做未來實現一個請求取決於兩個方面:該請求的名和接受者的類型。而雙分派意味着獲得執行的操做決定於請求的種類和兩個接受者的類型。solve是一個double dispatch操做,它的含義決定於兩個類型:Supporter的類型和Problem的類型。
 
解決這個問題,就是想辦法在運行時根據Problem和Supporter的具體類型進行分派。
在Problem中增長以下方法,在方法調用時將自身傳入。
class Problem 
{ 
public: 
     Problem(){} 
     virtual ~Problem(){}  
      virtual void solve(Supporter *s)
     {
          s->solve(*this);
     } 
     //*virtual void solve(SeniorSupporter *sp)
     //{
     //     sp->solve(*this);
     //}
};
在SpecialProblem,增長以下方法,在方法調用時,將自身傳入:
class SpecialProblem:public Problem 
{ 
public: 
     SpecialProblem(){} 
     ~SpecialProblem(){} 
      void solve(Supporter *s)
     {
          s->solve(*this);
     } 
     //void solve(SeniorSupporter *s)
     //{
     //     s->solve(*this);
     //}
};
看看如今的測試代碼:
int main() 
{ 
     Problem *p=new Problem(); 
     Problem *sp=new SpecialProblem(); 
     Supporter *s=new SeniorSupporter(); 
     p->solve(s); 
     sp->solve(s); 
     system("Pause"); 
     return 1; 
}

如下是運行結果: ci

 如今,經過調用:

p->solve(s);
sp->solve(s);

來實現兩次動態分派,第一次是problem中solve方法的多態,第二次是supporter中solve方法的多態。

Visitor模式也使用了相似的方式:

 
 

Visitor模式中的Accept也是一個double dispatch操做,它的含義決定於兩個類型:Visitor的類型和Element的類型。這是Visitor模式的關鍵所在:獲得執行的操做不只決定於Visitor的類型還決定於它訪問的Element的類型。而採起的解決方案如上圖,沒有將操做靜態的綁定在Element接口中,而是將其安放在一個Visitor中,並使用Accept在運行時進行綁定。


您的認真閱讀我將不勝榮幸,您的指正修改我將萬分感激。

版權全部,翻版不究,請註明出處便可。

相關文章
相關標籤/搜索