1. 什么是Multi-methods.
在闡述這個(gè)概念之前,我們先看一下什么是多態(tài)(Polymorphisn)。多態(tài)是面向?qū)?
象程序設(shè)計(jì)的一個(gè)重要的特征, 多態(tài)是允許你將父對(duì)象的指針(或者引用)設(shè)置成為它的子對(duì)象的技術(shù),賦值之后,該父對(duì)象指針(或者引用)就可以根據(jù)當(dāng)前賦
值給它的子對(duì)象的特性以不同的方式運(yùn)作。簡(jiǎn)單的說(shuō),就是一句話:允許將子類(lèi)類(lèi)型的指針賦值給父類(lèi)類(lèi)型的指針。多態(tài)性在C++中都是通過(guò)虛函數(shù)
(Virtual Function) 實(shí)現(xiàn)的。 例如:
class Parent

......{
public:
virtual void Test() = 0;
}

class Sub1: public Parent

......{
public:
void Test()

......{
cout<<"HI, this is sub1"<<endl;
}
}
class Sub2: public Parent

......{
void Test()

......{
cout<<"HI, this is sub2"<<endl;
}
}

Parent* p1 = new Sub1();
Parent* p2 = new Sub2();
p1->Test(); //call the Test method of class Sub1;
p2->Test();//call the Test method of class Sub1;


在c
++中,多態(tài)性的內(nèi)涵是:通過(guò)virtual function技術(shù),真實(shí)的函數(shù)調(diào)用完全依賴于對(duì)象的真實(shí)類(lèi)型(這就是late
binding)。我們的問(wèn)題是:virtual function調(diào)用可不可以依賴于兩個(gè)或者兩個(gè)以上的對(duì)象?這就是multi-methods.
例子:
//method declaration
bool intersect(const Shape&, const Shape&,)

......{
//...
}
bool intersect(const Rectangle&, const Circle&,)

......{
//...
}

class Shape

......{
//...
}
class Rectangle: public Shape

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

......{
//...
}

Shape* s1 = new Rectangle();
Shape* s2 = new Circle();

//while calling the following method, what happend?
//the actual function which will be called is bool intersect(const Shape&, const Shape&,), not bool intersect(const Rectangle&, const Circle&,)
// but what we want is the latter, not former
intersect(*s1,*s2);
//maybe you can call like this, which will meet our requirement, but, unfor?tunately , it violats the principle: we should program based on interface not implementation.
intersect(*(dynamic_cast<Rectangle*>(s1)),*(dynamic_cast<Circle*>(s2)));




2. C++ committee曾經(jīng)考慮的解決方案(摘自 The Design and Evolution of C++, by Stroustrup)
c++從語(yǔ)言自身來(lái)支持multi-method:
//solution 1:
(s1@s2)->intersect(); //rather than intersect(s1,s2);
//solution 2:
bool intersect(virtual const Shape&,virtual const Shape&);
bool intersect(virtual const Rectangle&,virtual const Circle&) //overrides

...{
}

或許,C++在將來(lái)的某個(gè)版本會(huì)支持multi-method.
3. workarounds for multi-method.
3.1 用double dispatch設(shè)計(jì)模式解決。
double dispatch(雙分派)設(shè)計(jì)模式是指:在選擇一個(gè)方法的時(shí)候,不僅僅要根據(jù)消息接收者(receiver)的運(yùn)行時(shí)型別(Run time type),還要根據(jù)參數(shù)的運(yùn)行時(shí)型別(Run time type)。接下來(lái)我們用double dispatch來(lái)解決一下上面的那個(gè)問(wèn)題:
class Shape

......{
//...
virtual bool intersect(const Shape&) const = 0;
virtual bool intersect(const Rectangle&) const = 0;
virtual bool intersect(const Circle&) const =0;
}
class Rectangle: public Shape

......{
//...
bool intersect(const Shape& s) const

......{
return s.intersect(*this); // *this is a Rectangle and calling which intersect method totally depends on the real type of s!
}
bool intersect(const Rectangle&) const

......{
//...
}
bool intersect(const Circle&) const

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

......{
//...
bool intersect(const Shape& s) const

......{
return s.intersect(*this); // *this is a Circle and calling which intersect method totally depends on the real type of s!
}
bool intersect(const Rectangle&) const

......{
//...
}
bool intersect(const Circle&) const

......{
//...
}
}
對(duì)于double dispatch, 最大的問(wèn)題是:這樣的設(shè)計(jì)與類(lèi)的繼承結(jié)構(gòu)高度耦合,當(dāng)類(lèi)的繼承結(jié)構(gòu)改變后,會(huì)影響到現(xiàn)有的代碼。從上面的例子可以看到:Shape 類(lèi)是不應(yīng)該意識(shí)到它的子類(lèi)的存在。不過(guò)當(dāng)前的主流面向?qū)ο蟪绦蛟O(shè)計(jì)語(yǔ)言(C++/Java/C#等)都并不支持multi-method, 從這個(gè)意義上說(shuō):double dispatch還是一個(gè)合理,有效地解決方案
3.2 另一個(gè)可選的方案是RTTI。
bool intersect(const Shape& s1, const Shape& s2)

...{
//the follwing code, can implement by using index table, the key is the type_id of the real object(such as typeid(s1) and typeid(s2))
//the query result is the pointer to function (such as the pointer to function: bool intersect(const Rectangle&, const Circle&).
if( typeid(s1)==typeid(Rectangle) && typeid(s1)==typeid(Rectangle))

...{
intersect(*(dynamic_cast<Rectangle*>(s1)),*(dynamic_cast<Circle*>(s2)));
}
else if(...)

...{
//...
}

}
bool intersect(const Rectangle&, const Circle&,)

...{
//...
}

class Shape

.........{
//...
}
class Rectangle: public Shape

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

.........{
//...
}

Shape* s1 = new Rectangle();
Shape* s2 = new Circle();
//as a result , for the caller, the code is based on interface not implementation
intersect(*s1,*s2);




