最后,让我们来看一下在这点上C++和C#或Java的区别。如果我们把面试题的C++代码改写成相应的C#或JAVA代码,那么我们会发现编译C#和JAVA代码时都会报错。这是因为C#和JAVA都不允许子类里的重定义虚拟函数的访问权限比基类中相应的虚拟函数的访问权限更少。即当bar::f()是公有函数时,foo::f()也必须也是公有函数。
在对象的继承性和多态性上,C#和JAVA的设计者都不约而同地采用使基类、子类之间虚拟函数关系明确化的思路。
C# 引入了两个新的关键词:new和override。子类里的重定义函数必须使用new或者override。从面向对象程序设计的角度来讲,这种设计强制程序员对不同类间虚拟函数的多态性关系非常明确。关键字override只是明确声明相关函数是个重定义函数;关键字new事实上提供了一种终止虚拟函数链的办法。请看以下程序代码:
using System;
namespace Sample
{
class bar
{
public virtual void f() { Console.WriteLine("I am in bar."); }
}
class foo : bar
{
public override void f() { Console.WriteLine("I am in foo."); }
}
class wa : bar
{
public new void f() { Console.WriteLine("I am in wa."); }
}
class Program
{
static void Main(string[] args)
{
bar me = new foo();
me.f();
me = new wa();
me.f();
}
}
}
上面的程序代码段输出:
I am in foo.
I am in bar.
在JAVA里,所有公有和保护函数都是虚拟函数。换句话讲,只要可以继承的函数都是虚拟函数。JAVA也提供了一种终止虚拟函数多态性的办法:那就是使用final关键词。例如下面的代码段编译时会出错:因为foo::f()是final,所以wa类不能在定义f()。
class bar
{
public void f() { System.out.println("I am in bar.");}
};
class foo extends bar
{
public final void f() { System.out.println("I am in foo."); };
}
class wa extends foo
{
public final void f() { System.out.println("I am in wa."); }
}