class Parent ......{ public: virtualvoid 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;
//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, unfortunately , 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)
double dispatch(双分派)设计模式是指:在选择一个方法的时候,不仅仅要根据消息接收者(receiver)的运行时型别(Run time type),还要根据参数的运行时型别(Run time type)。接下来我们用double dispatch来解决一下上面的那个问题:
class Shape ......{ //... virtualbool intersect(const Shape&) const=0; virtualbool intersect(const Rectangle&) const=0; virtualbool 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 ......{ //... } }
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))); } elseif(...) ...{ //... } } 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);