sherrylso

C++博客 首页 新随笔 联系 聚合 管理
  18 Posts :: 0 Stories :: 124 Comments :: 0 Trackbacks

1. 什么是Multi-methods.

在阐述这个概念之前,我们先看一下什么是多态(Polymorphisn)。多态是面向对 象程序设计的一个重要的特征, 多态是允许你将父对象的指针(或者引用)设置成为它的子对象的技术,赋值之后,该父对象指针(或者引用)就可以根据当前赋 值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。多态性在C++中都是通过虚函数 (Virtual Function) 实现的。 例如:

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 ++中,多态性的内涵是:通过virtual function技术,真实的函数调用完全依赖于对象的真实类型(这就是late binding)。我们的问题是:virtual function调用可不可以依赖于两个或者两个以上的对象?这就是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曾经考虑的解决方案(摘自 The Design and Evolution of C++, by Stroustrup)

c++从语言自身来支持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++在将来的某个版本会支持multi-method.

3. workarounds for multi-method.

3.1 用double dispatch设计模式解决。

double dispatch(双分派)设计模式是指:在选择一个方法的时候,不仅仅要根据消息接收者(receiver)的运行时型别(Run time type,还要根据参数的运行时型别(Run time type。接下来我们用double dispatch来解决一下上面的那个问题:

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
...
{
//...
}

}

对于double dispatch, 最大的问题是:这样的设计与类的继承结构高度耦合,当类的继承结构改变后,会影响到现有的代码。从上面的例子可以看到:Shape 类是不应该意识到它的子类的存在。不过当前的主流面向对象程序设计语言(C++/Java/C#等)都并不支持multi-method, 从这个意义上说:double dispatch还是一个合理,有效地解决方案

3.2 另一个可选的方案是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);





posted on 2007-05-06 22:28 爱上龙卷风 阅读(2189) 评论(4)  编辑 收藏 引用

Feedback

# re: C++与double dispatch设计模式 2009-06-26 18:17 Dan
很好!明白这个东西了。  回复  更多评论
  

# re: C++与double dispatch设计模式[未登录] 2011-01-08 14:53 darren
个人感觉还是RTTI比较好,代码比较简洁一点。  回复  更多评论
  

# re: C++与double dispatch设计模式 2012-02-03 14:52 croma
這樣的意義何在呢?
抽象行為的精神不就是簡化程式碼嗎?

正常的情況下 應該是 Shape 的 class 定義出形狀的描述規則
並且在 Intersect 實做這個規則的計算方法

子類別只要實作出自己的形狀描述就好了

我們不在意執行階段他是什麼型態,只要他完成 Shape 的描述就好了













  回复  更多评论
  

# re: C++与double dispatch设计模式 2013-09-05 01:52 Wangsu

@croma

Shape shapes[]={new Circle(),new Rect(), new Something()...};

foreach(Shape shape in shapes)
{
intersect(shape,next shape);<<=這裡會在 Compiler time 就決定調用 bool intersect(const Shape&, const Shape&,)。
}
  回复  更多评论
  


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理