今天看了兩頁<<Generative Programming>>中關于計算機語言中的多態內容。多態形式有運行時與編譯時之分,名稱綁定與類型綁定之分,回顧以下c++的語言特征,發覺以這兩種區分方式都有對應的機制,就是c++在運行時的多態上內建的支持有些不夠。看下面的:

class Shape {
public:
  // interface declare...
};

class Triangle: public Shape {
public:
   //...
};

class Circle: public Shape {
public:
   //...
};

class Rect: public Shape {
public:
   //...
};

void drawCover(Shape& a, Shape& b)
{   // 畫出兩個形狀的覆蓋區的混合色

   // 1. 這里這么寫呢?
   // a 一種是找出一種適用于所有Shape的算法
   // b 還有一種是dynamic_cast + typeid + 暴力編碼,這使我想起了<<Modern C++>>中的最后一章,不過那里只解決了問題的一半
}

int main()
{
   Rect rt;
   Triangle tri;

   drawCover(rt, tri);
   return 0;
}

上述問題似乎很奇怪,為什么不這樣來:
void drawCover(Rect& rt, Triangle& tri) {...}
void drawCover(Rect& rt, Circle& tri) {...}
void drawCover(Circle& rt, Triangle& tri) {...}
void drawCover(Trianlge& rt, Rect& tri) {...}
......
這樣問題得以優雅的解決!
可不幸的是,一旦寫:
Shape& a = ...;
Shape& b = ...;
drawCover(a, b);
時,compiler說類型決議二義性,這是因為C++支持obj->foo()樣的單分派引起的。
很明顯,C++不支持運行時的雙分派機制。

而且,要是這個實現是某個廣泛發布的網絡程序的一部分,那我們要把上述的靜態綁定的代碼要不斷地發補丁了,每次更新時,用戶滿腹牢騷。

為了避免這種情形,一種是把這一部分從客戶端的程序中分離出來,成為某幾個server上的模塊,可是這樣顯得很不自然;另一種,這需要一種運行時的類型->計算過程的自動映射機制,使得以增量更新的方式在客戶端自動進行,并且周期性的剔除長久不用的模塊,用c++的繼承+虛函數吧,這又回到了void drawCover(Shape& a, Shape& b),可是基于“兩個類型未確定對象的多態”語言可不提供。

設想:
方案1:也是網游中流行的data driver的script語言   +   C++方案
方案2;只用c++,使待定對象的類型與處理函數的對應關系被注冊在某個地方(dispatcher),在以后的code中,根據提供的多個對象實例的實際類型,到dispatcher中去找對應的處理函數,然后call找到的處理函數。這個方案與AI技術中的board滿相似,是預知了問題的處理策略與處理場景,所以核心問題就是給場景中的對象打上標記,以備隨時查找使用,既C++中的RTTI(也可以使用自己的替代物)。

回顧一下,這里其實要實現一個"運行時的多分派機制",獲得的抽象concept有:dispatch \ regist \ find \ types \type identify \ call。



Draft:

// 先給類型ABCD,還有BaseType打上類型標記
// 打標記的代碼...

template<TypeList<A,B,C,D,...>, BaseType, ArgCount >=2>
class Dispatcher {
public:
   //...
   template<U,V,...,Function>
   void register(U& a, V& b, ...., Function fn);

   void run(BaseType& a, BaseType& b, ...);   // find by type id, and call it
};

還有許多細節問題,今天先到這里! :)