今天看了两页<<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
};
还有许多细节问题,今天先到这里! :)