一个C#类多态与隐藏(new)方法的结果分析

这个学期上了一门C#程序设计语言课,讲到面向对象的多态与重定义(new)时,发现了一个比较有趣的现象,即:virtual被派生类override后,再做派生时隐藏(new)并重定义该方法,运行的结果有点意思,现摘录如下,并尝试解释结果。

下面是程序代码:

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            G0 p = new G3();

            (p as G3).Say();
            (p as G2).Say();
            (p as G1).Say(); 
            (p as G0).Say();
        }
    }

    public class G0
    {
        public virtual void Say()  // 虚方法
        {
            Console.WriteLine("G0.");
        }
    }

    public class G1 : G0
    {
        public override void Say()  // 重写虚方法,多态方法
        {
            Console.WriteLine("G1.");
        }
    }

    public class G2 : G1
    {
        public new void Say()  // 隐藏了基类的多态方法
        {
            Console.WriteLine("G2.");
        }
    }

    public class G3 : G2
    {
        public new void Say()  // 继续隐藏
        {
            Console.WriteLine("G3.");
        }
    }
}

这段代码(VS2010+.NET 4.0)的运行结果如下图:


代码中变量p的类型为G0(祖宗类),然后指向一个G3的对象实例。接着转换为G3、G2、G1和G0,并调用方法Say(),根据上图可知:

  • (p as G3).Say()输出了G3。因为变量p是G3类型,此时调用G3的Say()方法输出“G3”是正常的,不存在所谓的多态。
  • (p as G2).Say()输出了G2。转换后临时变量(假设为tmp)的类型是G2,该类型与G3不同,此时有多态。但tmp.Say()是重定义方法(隐藏了基类的Say()),不是多态方法,于是直接调用G2类型的临时变量的Say()方法,并输出“G2”。
  • (p as G1).Say()输出了G1。因为G1和G3不同,即转换后的临时变量tmp类型与实例类型G3不同,且tmp.Say()有多态方法(override)。于是,按多态性将调用G3实例的多态方法,而G3实例没有多态的Say(),只有重定义的Say()方法,于是沿着继承逆向查找多态方法,找到G1为止,此时调用G1.Say(),输出“G1”。
  • (p as G0).Say()输出了G1。因为G0和G3不同,同上面的解释,此时仍然调用G1.Say()输出“G1”。

总结:

  • 变量类型与所指向的实例类型相同时,如G3 p = new G3(),将调用G3的方法Say(),不管该方法是否多态,均直接调用其实例的该方法。
  • 引用变量的类型与所指向的实例的类型不同时,如G0 p  = new G3(); G1 p = new G2();等,变量调用的方法有可能呈现多态性质:
    • 当变量类型的方法tmp.Say()为非多态方法时(new重定义),如 (p as G2).Say(),直接调用该非多态方法。
    • 当变量类型的方法tmp.Say()为多态方法时,如(p as G1).Say(),此时将调用该变量所指向的实例的多态方法。如果实例没有定义或重定义了该方法,则沿着继承逆向查找最近的多态方法。

上述为个人的一点理解,可以解释程序运行的结果,特别是(p as G0).Say()的结果是“G1”而不是“G0”。该解释是否正确待继续探讨与确认。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值