C#中的new与Override的区别?

大漠刀客
  • 185
using System;

namespace 重写父类方法
{
    class Father
    {
        public void F_Out()
        {
            this.OutPut();
        }

        public  void OutPut()
        {
            Console.WriteLine("调用父类OutPut方法");
        }
    }

    class Sub : Father
    {
        public new void OutPut()
        {
            Console.WriteLine("调用子类OutPut方法");
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
            Sub sub = new Sub();
            sub.F_Out();
        }
    }
}

上面输出调用父类OutPut方法
没明白为什么隐藏父类的OutPut方法会造成这样的结果, this.OutPut();应该就是是sub.OutPut()所以调用的应该是子类的OutPut方法啊,然后使用重写的方法正确了。没明白怎么回事,不管怎么样,this.OutPut就应该是sub.OutPut?

using System;

namespace 重写父类方法
{
    class Father
    {
        public void F_Out()
        {
            this.OutPut();
        }

        public virtual void OutPut()
        {
            Console.WriteLine("调用父类OutPut方法");
        }
    }

    class Sub : Father
    {
        public override void OutPut()
        {
            Console.WriteLine("调用子类OutPut方法");
        }
    }


    class Program
    {
        static void Main(string[] args)
        {
            Sub sub = new Sub();
            sub.F_Out();
        }
    }
}

下面这个输出调用子类OutPut方法。

回复
阅读 1.5k
1 个回答

真是个很好的问题以及示例(起码对我个人而言是这样的)。
以下是我的理解以及参考。

new

微软文档 new 修饰符 中有这么一句话:

在用作声明修饰符时,new 关键字可以显式隐藏从基类继承的成员。

我的理解是,这个隐藏仅仅只是针对派生类而言的,并没有对基类造成任何影响。

Override

微软文档 virtual 关键字 中有这么一句话:

调用虚拟方法时,将为替代的成员检查该对象的运行时类型。

我的理解是:使用了 virtual 关键字的成员,在运行时,才会确定其当前所属的对象的具体类型。

此时,通过 override 的示例代码中的 new Sub() 执行 F_Out(),程序会确定对象实际类型是 Sub,所以,会执行 SubOutPut

在网上一些其他资料中,大致搜集到这么一个结论:
从编译角度讲:
普通成员在编译时,其引用的相对地址就已经被程序确定好了。因此程序运行时,将会直接根据该地址调用该成员。即:在编译时,new 的示例代码中的 FatherF_Out 方法中,就已经把 OutPut 方法的引用确定好了(也就是 FatherOutPut 方法的引用)。
而虚成员在编译时,并没有将其引用固定写在程序的执行文件。因此程序运行时,才会检查当前对象(也就是类的实例)到底是什么类型。当该对象调用虚成员时,会发现该成员是虚成员,然后就会查找它的重写成员。从该实例的具体类型开始,一层一层地向上(即其父类)查找,找到后就会执行。即:override 的示例代码中的 Sub 实例化后,调用其基类中的 F_Out 时,程序还不知道 OutPut 的具体引用地址。查找后发现这个虚方法的第一个重写就是 Sub 中的 OutPut,因此,就开始执行它了。

个人浅见,我会把这个问题分享给身边同事。如果有更深入的理解,我会及时更新。

宣传栏