// Code #01 class Base { public virtual void PrintStatus() { Console.WriteLine("public virtual void PrintStatus() in Base"); } } |
// Code #02 public void DisplayStatusOf(Base[] bs) { foreach (Base b in bs) { b.PrintStatus(); } } |
public static XmlReader Create(Stream input); |
// Code #03 class Derived1 : Base { public override void PrintStatus() { Console.WriteLine("public override void PrintStatus() in Derived1"); } } |
// Code #04 class Derived2 : Base { public new void PrintStatus() { Console.WriteLine("public new void PrintStatus() in Derived2"); } } |
Base[] bs = new Base[] { new Base(), new Derived1(), new Derived2() }; |
// Output #01 // public virtual void PrintStatus() in Base // public override void PrintStatus() in Derived1 // public virtual void PrintStatus() in Base |
// Code #06 Base d2 = new Derived2(); d2.PrintStatus(); // Output #02 // public virtual void PrintStatus() in Base 而在 Derived2 内部,你可以透过 base 来访问: // Code #07 base.PrintStatus(); |
// Code #08 interface IFace { void PrintStatus(); } class Base : IFace { public virtual void PrintStatus() { Console.WriteLine("public virtual void PrintStatus() in Base"); } } |
// Code #09 class Derived2 : Base, IFace { public new void PrintStatus() { Console.WriteLine("public new void PrintStatus() in Derived2"); } } |
// Code #10 IFace[] fs = new IFace[] { new Base(), new Derived1(), new Derived2(), } |
// Code #11 public void DisplayStatusOf(IFace[] fs) { foreach (IFace f in fs) { f.PrintStatus(); } } |
// Output #03 // public virtual void PrintStatus() in Base // public override void PrintStatus() in Derived1 // public new void PrintStatus() in Derived2 |
从输出结果中,我们可以看到,虽然 Derived2.PrintStatus 应用了 new,但却依然参与动态绑定,这是由于 new 只能割断 Derived2.PrintStatus 和 Base.PrintStatus 的联系,而不能割断它与 IFace.PrintStatus 的联系。我在 Derived2 的定义中重新指定实现 IFace,这将使得编译器认为 Derived2.PrintStatus 是 IFace.PrintStatus 的隐式实现,于是,在动态绑定时 Derived2.PrintStatus 就被包括进来了
精品教程尽在www.xvna.com
5. 谁的问题?
我必须指出,如果 Base(Code #01)和 Derived2(Code #04)同时存在的话,它们俩其中一个存在着设计上的问题。为什么这样说呢?Base 的设计者在 PrintStatus 上应用 virtual 说明了他希望派生类能透过重写这一方法来参与动态绑定,即多态性;而 Derived2 的设计者在 PrintStatus 上应用 new 则说明了他希望割断 Derived2.PrintStatus 和 Base.PrintStatus 之间的联系,这将使得 Derived2.PrintStatus 无法参与到 Base 的设计者所期望的动态绑定中。如果在 Base.PrintStatus 上应用 virtual(即对多态性的期望)是合理的话,那么 Derived2.PrintStatus 应该换用另外一个名字了;如果在 Derived2.PrintStatus 上应用 new(即否决参与动态绑定)是合理的,那么 Base.PrintStatus 应该考虑是否去掉 virtual 了,否则就会出现一些奇怪的行为,例如 Output #01 的第三行输出。
假如继承体系中多态性行为的期望是合理的话,那么更实际的做法应该是把 Base 定义成这样:
// Code #12 abstract class Base { public abstract void PrintStatus(); } |
class Derived3 : Base { public override void PrintStatus() { Console.WriteLine("public override void PrintStatus() in Derived3 [originally implemented in Base]"); } } |
public abstract long Seek(long offset, SeekOrigin origin); |
// Code #14 public void Resume(Stream input, long offset) { // input.Seek(offset, SeekOrigin.Begin); // } |
// Code #15 public void Resume(Stream input, long offset) { if (input.CanSeek) { // input.Seek(offset, SeekOrigin.Begin); // } else { // } } |