关于C#中的new修饰符以及override关键字

今天一朋友问我,C#中 new 与 override 有什么区别?
附上原问题导航C#中的new与Override的区别?(SF上的各位都是朋友,嘿嘿)。
刚看到这个问题,其实我有点懵,由于我对这两个关键字的研究也没有花太多心思,虽然知道一些区别,但并非很是确信。
因此,趁着此次机会,本身也学习一下。c#

首先,原问题中的示例代码给了我很是好的参考。这段代码很是直观地体现了newoverride的区别。segmentfault

下面是我略加整理的测试代码:ide

new修饰符

代码

public class FatherNew
{
    public void DoConsole()
    {
        Console.WriteLine("New修饰符 => 父类。");
    }

    public void ConsoleFather()
    {
        DoConsole();
    }
}

public class ChildNew : FatherNew
{
    public new void DoConsole()
    {
        Console.WriteLine("New修饰符 => 子类。");
    }

    public void ConsoleFatherCopy()
    {
        DoConsole();
    }
}
// 客户端调用
var cn = new ChildNew();
cn.ConsoleFather();
// cn.ConsoleFatherCopy(); // 这一句会输出 "New修饰符 => 子类。",具体缘由结论中会说明。

代码中,咱们使用new隐藏了父类(FatherNew)的DoConsole方法。
看看它的运行结果吧。学习

运行结果

new result

那么问题来了:咱们明明把FatherDoConsole方法覆盖掉了,理论上ConsoleFather()执行的时候应该调用新的DoConsole呀,这样的话,应该输出"New修饰符 => 子类。"才对呀。测试

这个疑惑我们先放放,先看一下override的代码及结果我们再统一总结。spa

override修饰符

代码

public class FatherOverride
{
    public virtual void DoConsole()
    {
        Console.WriteLine("Override修饰符 => 父类。");
    }
    public void ConsoleFather()
    {
        DoConsole();
    }
}

public class ChildOverride : FatherOverride
{
    public override void DoConsole()
    {
        Console.WriteLine("Override修饰符 => 子类。");
    }

    public void ConsoleFatherCopy()
    {
        DoConsole();
    }
}
// 客户端调用
var co = new ChildOverride();
co.ConsoleFather();

就像new里的代码同样,咱们重写了父类(FatherOverride)的DoConsole方法,只不过此次是用override修饰符。
也看看运行结果吧:code

运行结果

override result

这个还算符合预期,既然我重写了DoConsole,那么执行时,就应该执行调用新的DoConsole才对嘛。对象

结论

new修饰符定义的新方法,在同一派生类调用时,的确会调用这个新的方法,但在其基类中调用时,依旧是调用基类中的那个原始的方法。
override修饰符重写的方法,只要是经过派生类实例调用,哪怕是间接调用(好比像示例代码中,派生类的示例,调用父类中的ConsoleFather方法),都会调用新的使用override重写的那个方法。blog

之因此出现这种状况,是由于在编译时,它们就已经有了差别:get

普通成员在编译时,其引用的相对地址就已经被程序肯定好了。所以程序运行时,将会直接根据编译时就肯定好了的地址调用该成员。即:在编译时, FatherNewConsoleFather方法就已经肯定了它内部持有的 DoConsole方法就是 FatherNewDoConsole方法。所以,程序运行时,天然也就会调用 FatherNewDoConsole方法,因此,输出的结果固然也就是 "New修饰符 => 父类。"了。
cn.ConsoleFatherCopy()之因此会输出 "New修饰符 => 子类。",也是由于 ChildNew在编译时,就已经决定了 ConsoleFatherCopy中持有的是 ChildNewDoConsole方法的引用。

而虚成员在编译时,并无将其引用固定写在程序的执行文件中。所以程序运行时,才会检查当前对象(也就是类的实例)究竟是什么类型。当该对象调用虚成员时,会发现该成员是虚成员,而后就会查找它的重写成员。从该实例的类开始,一层一层地向上(即其父类)查找,找到后就会执行。即:ChildOverride实例化后,调用其基类中的ConsoleFather时,程序还不知道DoConsole的具体引用地址。查找后发现这个虚方法的第一个重写就是ChildOverride中的DoConsole,所以,就执行它了。

相关文章
相关标签/搜索