首页 > 代码库 > 设计模式:多重派遣

设计模式:多重派遣

在面向对象程序设计中,非常常用的手法就是用基类的指针指向派生类,然后在执行期通过虚函数机制找到派生类中的函数,假设这样一种情况,全局函数有两个输入参数,分别是两个基类指针 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选择正确的函数重载版本。





设计模式:多重派遣