看一段简单的C++代码
- #include <iostream>
- class A
- {
- public:
- void f(float x)
- {
- std::cout << "A::f(float)" << std::endl;
- }
- void f(int x, int y)
- {
- std::cout << "A::f(int,int)" << std::endl;
- }
- };
- class B : public A
- {
- public:
- void f(int x)
- {
- std::cout << "B::f(int)" << std::endl;
- }
- };
- int main(int argc, char * argv[])
- {
- B b;
- b.f(2.3);
- // b.f(2,3); occur error
- return 1;
- }
执行结果应该是什么呢?
记住这种情况不会实现函数重载的,因此调用b.f(2,3)会出现编译错误,而调用b.f(2.3)不会调用基类的f函数,而会调用派生类的f函数(参数类型隐性转换),函数隐藏的概念摘录如下
隐藏是指派生类的函数屏蔽了与其同名的基类函数,规则如下:
- 如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)
- 如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)
再看同样代码的C#实现
- using System;
- using System.Collections.Generic;
- using System.Text;
- namespace FunctionTest
- {
- class Program
- {
- static void Main(string[] args)
- {
- B b = new B();
- b.f(2.3f);
- b.f(2, 3); // work well
- }
- }
- public class A
- {
- public void f(int x)
- {
- Console.WriteLine("A::f(int)");
- }
- public void f(int x, int y)
- {
- Console.WriteLine("A::f(int,int)");
- }
- }
- public class B : A
- {
- public void f(float x)
- {
- Console.WriteLine("B::f(float)");
- }
- }
- }
会发现与C++的不同之处,在C#中不会进行函数隐藏,即使派生类与基类同名,参数不同也能实现类似函数重载,执行结果是
A::f(float)
A::f(int,int)
这样的结果才会符合我们预期的设想,也许这也算是C++设计的一个不足之处吧
为了验证这真的算是函数重载么,把上面的程序简单改变一下,再看下面一段C#代码
- using System;
- using System.Collections.Generic;
- using System.Text;
- namespace FunctionTest
- {
- class Program
- {
- static void Main(string[] args)
- {
- B b = new B();
- b.f(2);
- b.f(2, 3); // work well
- }
- }
- public class A
- {
- public void f(int x)
- {
- Console.WriteLine("A::f(int)");
- }
- public void f(int x, int y)
- {
- Console.WriteLine("A::f(int,int)");
- }
- }
- public class B : A
- {
- public void f(float x)
- {
- Console.WriteLine("B::f(float)");
- }
- }
- }
执行结果是
B::f(float)
A::f(int,int)
此时为什么没有调用基类的函数呢 这与普通的函数重载肯定也有不同之处,我的理解是派生类中的函数会有比基类更高的优先级,int能直接转换为float型,然后进行调用,反之float转换成int,是不能隐式进行的,所以调用了基类的函数。这只是我的理解,如果有更好的解释情留言告诉我。