why C++ double dispatch”。
?
在多年的工作中,我已经养成了一种固定的学习习惯。例如对于一个知识点,我常常首先了解How,即它是如何工作的;然后是Why,也就是为什么按照这样的方式来工作;然后才是When,即在知道了为什么按照这样的方式来工作后,我们才能在适当的情况下使用它。
?
幸运的是,在很多
论坛中已经讨论过为什么这些语言不直接支持Double Dispatch了。简单地说,一个语言常常不能支持所有的功能,否则这个语言将会变得非常复杂,编写它的编译器及运行时也将变成非常困难的事情。因此到底支持哪些功能实际上由一个语言的目标领域所决定的。在一个语言可以通过一种简单明了的方式解决一种特定问题的时候,该语言就不再必须为该特定问题提供一个内置的解决方案。这些解决方案会逐渐固定下来,并被赋予了一个特有的名字。例如
C++中的一种常用模式就是Observer。该模式实现起来非常简单,也易于理解。而在其它语言中就可能提供了对Observer的原生支持,如C#中的delegate。而Visitor模式实际上就是C++对Double Dispatch功能的标准模拟。
?
接下来,我又搜索了几个Visitor模式的标准实现并开始比较自己所实现的Double Dispatch与Visitor模式标准实现之间的不同之处。这又是我的另一个习惯:实践常常可以检验出自己对于某个知识点的理解是否有偏差。就像我刚刚所犯下的对重载决议的理解错误一样,形成自己解决方案的过程常常会使自己理解某项技术为什么这么做有更深的理解。而通过对比自己的解决方案和标准解决方案,我可以发现别人所做的一些非常精巧的解决方案,并标准化自己的实现。
?
我仔细地检查了自己刚才所写的有关销售汽车的实例与标准Visitor模式实现之间的不同。显然Visitor模式的标准实现更为聪明:在Sales和SalesManager的成员函数中,编译器知道this所指向的实例的类型,因此将*this当作参数传入到函数中就可以正确地利用C++所提供的函数重载决议功能。这比我那种在实现中调用不同函数的方法高明了不知多少:
?
?
1 class SalesManager : public Sales
2 {
3 public:
4 ? ? virtual double GetDiscountRate(Vehicle& vehicle)
5 ? ? {
6 ? ? ? ? return vehicle.GetDiscountRate(*this); <----编译器知道*this是SalesManager类型实例,因此可以正确地选择接受SalesManager类型参数的重载
7 ? ? }
8 };
?
那么在Vehicle类以及Benz类中,我们只需要创建接收不同类型参数的函数重载即可:
?
1 class Benz : public Vehicle
2 {
3 public:
4 ? ? virtual double GetDiscountRate(Sales& sales) { return 0.06; }
5 ? ? virtual double GetDiscountRate(SalesManager& salesManager) { return 0.066; }
6 };
而在Visitor模式的标准实现中,我们则需要使用Visit()及Accept()函数对替换上面的各成员函数,并为所诱得汽车及销售人员定义一个公共接口。因此对于上面的销售汽车的示例,其标准的Visitor模式实现为:
?
?
?1 class Sales;
?2 class SalesManager;
?3?
?4 // 汽车接口
?5 class IVehicle
?6 {
?7 public:
?8 ? ? virtual double Visit(Sales& sales) = 0;
?9 ? ? virtual double Visit(SalesManager& sales) = 0;
10 };
11?
12 // 普通汽车,折扣为0.03
13 class Vehicle : public IVehicle
14 {
15 public:
16 ? ? virtual double Visit(Sales& sales) { return 0.03; }
17 ? ? virtual double Visit(SalesManager& salesManager) { return 0.03; }
18 };
19?
20 // 由于是奔驰特销商,因此可以得到更大的折扣
21 class Benz : public IVehicle
22 {
23 public:
24 ? ? virtual double Visit(Sales& sales) { return 0.06; }
25 ? ? virtual double Visit(SalesManager& salesManager) { return 0.066; }
26 };
27?
28 class ISales
29 {
30 public:
31 ? ? virtual double Accept(IVehicle& vehicle) = 0;
32 };
33?
34 // 普通的销售人员,只能按照公司规定的折扣进行销售
35 class Sales : public ISales
36 {
37 public:
38 ? ? virtual double Accept(IVehicle& vehicle)
39 ? ? {
40 ? ? ? ? return vehicle.Visit(*this);
41 ? ? }
42 };
43?
44 // 销售经理,可以针对某些车型提供额外的优惠
45 class SalesManager : public ISales
46 {
47 public:
48 ? ? virtual double Accept(IVehicle& vehicle)
49 ? ? {
50 ? ? ? ? return vehicle.Visit(*this);
51 ? ? }
52 };
53?
54 int _tmain(int argc, _TCHAR* argv[])
55 {
56 ? ? // 需要销售的两辆车
57 ? ? Vehicle& vehicle = Vehicle();
58 ? ? Benz& benz = Benz();
59?
60 ? ? // 向普通销售询问这两辆车的折扣
61 ? ? Sales* pSales = new Sales();
62 ? ? double rate = pSales->Accept(vehicle);
63 ? ? cout << "Sales: The rate for common vehicle is: " << rate << endl;
64 ? ? rate = pSales->Accept(benz);
65 ? ? cout << "Sales: The rate for benz is: " << rate << endl;
66?
67 ? ? // 向销售经理询问这两辆车的折扣
68 ? ? SalesManager* pSalesManager = new SalesManager();
69 ? ? rate = pSalesManager->Accept(vehicle);
70 ? ? cout << "Sales Manager: The rate for common vehicle is: " << rate << endl;
71 ? ? rate = pSalesManager->Accept(benz);
72 ? ? cout << "Sales Manager: The rate for benz is: " << rate << endl;
73?
74 ? ? return 0;
75 }
?
“那Visito