在面向对象程序设计中,非常常用的手法就是用基类的指针指向派生类,然后在执行期通过虚函数机制找到派生类中的函数,假设这样一种情况,全局函数有两个输入参数,分别是两个基类指针 A* ap 和 B* bp,那么如何既找到ap指向的准确对象,又找到bp指向的准确对象呢?答案就是多重派遣,既先找到ap(bp)指向的准确对象,再去寻找bp(ap)指向的准确对象,代码示例如下:
#include <iostream>
using namespace std;
class A {
public:
virtual void funca() { cout<<"Base A"<<endl; }
};
class A1 : public A {
public:
void funca() { cout<<"Derived A1"<<endl; }
};
class A2 : public A {
public:
void funca() { cout<<"Derived A2"<<endl; }
};
class B {
public:
virtual void funcb(A *p) {
cout<<"Base B"<<endl;
p->funca();
}
};
class B1 : public B {
public:
void funcb(A *p) {
cout<<"Derived B1"<<endl;
p->funca();
}
};
class B2 : public B {
public:
void funcb(A *p) {
cout<<"Derived B2"<<endl;
p->funca();
}
};
void func(A *a, B* b) { b->funcb(a); }
int main(){
B *bp = new B1();
A *ap = new A1();
func(ap,bp);
return 0;
}
在上面的例子中,func(A*, B*)就是前面所说的全局函数,最后通过两层虚函数调用将ap和bp指向正确的派生类对象。当然,实现多重派遣不只这一种方法,也可以通过重载的方式来实现,如下:
class B {
public:
void funcb(A *p) {
cout<<"Base B"<<endl;
cout<<"Base A"<<endl;;
}
void funcb(A1 *p) {
cout<<"Base B"<<endl;
cout<<"Derived A1"<<endl;
}
void funcb(A2 *p) {
cout<<"Base B"<<endl;
cout<<"Derived A2"<<endl;
}
};
在这种情况下,B需要知道A有哪些派生类,然后为A的每一个派生类定义一个函数的重载版本,在A中可以通过将this指针传递给对B的调用,如下:
class A {
public:
virtual void funca(B *p) {
p->funcb(this);
}
};
class A1 : public A {
public:
void funca(B *p) {
p->funcb(this);
}
};
class A2 : public A {
public:
void funca(B *p) {
p->funcb(this);
}
};
全局函数的定义如下:
void func(A *ap, B* bp) { ap->funca(bp); }
这样首先通过虚函数调用找到了A的派生类对象,然后在A的派生类对象中将this指针传给对B的调用,而此时传进去的this指针已经是派生类的指针,所以可以帮助B选择正确的函数重载版本。