昨天和一个群(Rust)友聊天,大家讨论静多态,动多态,然后一个朋友说静多态实现是基于重载的。后来我们还私聊了半天,他总是问我“模板结果就是重载!”,承认不承认。
首先,我的观点是,重载不算是多态。第二,我当时不理解他说的模板结果就是重载的含义(所以不能轻易说承认,或者否认),然后他多次提到this指针的实现:实际上是函数调用的一个参数。
后来我想明白他的逻辑了:...是这样的,咱们进入正题。
A : C<A> 省略一切和问题无关的语言要素,例如public修饰等等。
B : C<A>
这里A和B是两个无关的类,不存在父子关系。然后静多态是在基类C 类模板中进行的调用的(这是大家都知道的了),问题就在于A::f(1) 和 B::f(1)的调用上。
我想明白他的逻辑是这样的:
A::f(1) 基本等效于 f( (A*)pThis, 1); 【这就算是个人人共知的事情吧,】
那么B::f(1)就是 f( (B*)pThis, 1 );了。
那么 f( (A*)pThis, 1)和 f( (B*)pThis, 1 );当然是重载的关系了。
-------------------------------------------------------------------------------------------------------------
这个应该就是他的理论基础了。所以我现在给出明确的回答好了, 模板结果就是重载 是 错误的!
模板结果就是重载 是 错误的! 模板结果就是重载 是 错误的!(知乎体)
再次进入论证,
1. 正面的证明就是,C++定义overload函数,有明确的说明,函数同名,且在一个Scope内。
参看【http://stackoverflow.com/questions/429125/override-and-overload-in-c】里面说,Overloading generally means that you have two or more functions in the same scope having the same name.
所以,A::f(int)和B::f(int)根据定义就不是互为重载的。至于,this指针也是一个参数,这个只是帮助初学者理解this的一个办法,然而二者并不是等价的。
1.1 二者当然不是等价的了【证明二者不是等价的】
a->f(1);
和
f(a, 1);
是不等价的,前者是有可能发生动多态调用的,而后者的写法,是怎么都不会发生这个动多态调用的情况的,所以你理解的【A::f(1) 基本等效于 f( (A*)pThis, 1)】只是一个理解。
1.2 当然,你可能还是觉得不服气,觉得在实现上,就是等价的,就是基于重载的。
那么按照你的等价观点,max(int, int)和std::max(int, int)也是互为重载的,但是显然不是啊。
2. 反面的证明(就是你说的反证)
首先,C++编译一个函数,是有一个固定的顺序的, 1) Name Look Up(命名查找),2) Resolution (重载决议) 3) 可访问性检查
那么:当你调用a->f(1, 2); 就会先发生命名查找,
然后:如果A::f(int)和B::f(int)互为重载函数的话,那么A::f(int)和B::f(int, int)也就互为重载了。【这个推论是显而易见的吧?】
那么结果应该是A范围内找到f(int)函数,B范围内找到f(int, int),然后进行重载决议。然而,第一个参数类型是不匹配的。编译器就会报你们写重载函数类型不匹配的编译错误。
然而,结果将是编译报错,说找不到f(int, int)。
也就是说,命名查找这关就过不去,而不是重载决议过不去。因为A::f(...)和B::f(...)就不是重载函数。
所以,根据正反两种证明,模板结果就是重载 是 错误的!
写在最后,A::f(1) 基本等效于 f( (A*)pThis, 1),只是在某些情况下便于你理解this,然而不是在任何时候都是正确的。否则max, std::max, boost::max, ClassA::max不都是重载了吗? (呵呵)