ate();
7 ? ? }
8 ? ? ……
9 };
?
难道我对函数重载的理解不对?在搜索引擎中键入“
C++ overload resolution”,我打开了
C++标准中有关函数重载决议的讲解。其开始的一段话就给了我答案:
?
In order to compile a function call, the compiler must first perform name lookup, which, for functions, may involve argument-dependent lookup, and for function templates may be followed by template argument deduction. If these steps produce more than one candidate function, then overload resolution is performed to select the function that will actually be called.
?
哦,对!函数重载决议是在编译时完成的。也正因为我们传入的是Vehicle类型的引用,编译器并没有办法知道在运行时传入GetDiscountRate()这个函数的参数到底是Vehicle实例还是Benz实例,因此编译器只可能选择调用接受Vehicle类型引用的重载。如果传入参数benz的类型不再是Vehicle的引用,而是更具体的Benz的引用,那么编译器将会正确地决定到底其所需要调用的函数:
?
?
?
但这就不再是根据参数的类型动态决定需要调用的逻辑了,也就不再是Double Dispatch了。要如何达到这种效果呢?我苦苦地思索着。
?
“你在想什么?”身边的同事递给我今天公司派发的水果,一边吃着一边问我。我就把我刚刚写出的程序以及我现在正在考虑的问题告诉了他。
?
“既然你要动态决定需要调用的逻辑,那么就把这些逻辑放到动态运行的地方去啊,比如说放到你那些汽车类里面然后暴露一个虚函数,就可以根据所传入的汽车类型决定该汽车所需要使用的折扣率了啊。”
?
“哦对”,我恍然大悟。C++在运行时动态决议的基本方法就是虚函数,也就是一种Single Dispatch,如果依次在对象和传入参数上连续调用两次虚函数,那么它不就是Double Dispatch了么?在销售汽车这个例子中,我希望同时根据销售人员的职称和所销售的汽车类型一起决定需要执行的逻辑。那么我们首先需要通过Sales类型的指针调用一个虚函数,从而可以根据销售人员的实际类型来决定其在销售时所需要执行的实际逻辑。而在执行这些逻辑的过程中,我们还可以继续调用传入参数实例上定义的虚函数,就可以根据传入参数的类型来决定需要执行的逻辑了!
?
说做就做。我在Vehicle类中添加一个新的虚函数GetManagerDiscountRate(),以允许SalesManager类的函数实现中调用以获得销售经理所能拿到的折扣,并在Benz类中重写它以返回针对奔驰的特有折扣率。而在Sales以及SalesManager类的实现中,我们则需要分别调用GetBaseDiscountRate()以及新的GetManagerDiscountRate()函数来分别返回普通销售和销售经理所能拿到的折扣率。通过这种方式,我们就可以同时根据销售人员的职务以及所销售车型来共同决定所使用的折扣率了。更改后的代码如下所示:
?
?
?1 // 普通汽车,折扣为0.03
?2 class Vehicle
?3 {
?4 public:
?5 ? ? virtual double GetBaseDiscountRate() { return 0.03; }
?6 ? ? virtual double GetManagerDiscountRate() { return 0.03; }
?7 };
?8?
?9 // 由于是奔驰特销商,因此可以得到更大的折扣
10 class Benz : public Vehicle
11 {
12 public:
13 ? ? virtual double GetBaseDiscountRate() { return 0.06; }
14 ? ? virtual double GetManagerDiscountRate() { return 0.066; }
15 };
16?
17 // 普通的销售人员,只能按照公司规定的折扣进行销售
18 class Sales
19 {
20 public:
21 ? ? virtual double GetDiscountRate(Vehicle& vehicle)
22 ? ? {
23 ? ? ? ? return vehicle.GetBaseDiscountRate();
24 ? ? }
25 };
26?
27 // 销售经理,可以针对某些车型提供额外的优惠
28 class SalesManager : public Sales
29 {
30 public:
31 ? ? virtual double GetDiscountRate(Vehicle& vehicle)
32 ? ? {
33 ? ? ? ? return vehicle.GetManagerDiscountRate();
34 ? ? }
35 };
36?
37 int _tmain(int argc, _TCHAR* argv[])
38 {
39 ? ? // 需要销售的两辆车
40 ? ? Vehicle& vehicle = Vehicle();
41 ? ? Benz& benz = Benz();
42?
43 ? ? // 向普通销售询问这两辆车的折扣
44 ? ? Sales* pSales = new Sales();
45 ? ? double rate = pSales->GetDiscountRate(vehicle);
46 ? ? cout << "Sales: The rate for common vehicle is: " << rate << endl;
47 ? ? rate = pSales->GetDiscountRate(benz);
48 ? ? cout << "Sales: The rate for benz is: " << rate << endl;
49?
50 ? ? // 向销售经理询问这两辆车的折扣
51 ? ? SalesManager* pSalesManager = new SalesManager();
52 ? ? rate = pSalesManager->GetDiscountRate(vehicle);
53 ? ? cout << "Sales Manager: The rate for common vehicle is: " << rate << endl;
54 ? ? rate = pSalesManager->GetDiscountRate(benz);
55 ? ? cout << "Sales Manager: The rate for benz is: " << rate << endl;
56?
57 ? ? return 0;
58 }
?
再次运行程序,我发现现在已经可以得到正确的结果了:
?
?
?
也就是说,我自创的Double Dispatch实现已经能够正确地运行了。
?
?
?
你好,Visitor
?
“你说为什么C++这些高级语言不直接支持Double Dispatch?”我问身边正在和水果奋斗的同事。
?
“不需要呗。”他头也不抬,随口回答了一句,又拿起了另一只水果。
?
话说,他可真能吃。
?
“真的不需要么?”我心里想,就又在搜索引擎中输入了“