zoukankan      html  css  js  c++  java
  • [原创]C#中的继承、重写、覆盖、多态、virtual override 以及其他

    参考:《C#本质论》

    例子:

        
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
        public class BaseClass    {
            public virtual void displayName()
            {
                Console.WriteLine("BaseClass");
            }
        }
    
        public class DerivedClass : BaseClass
        {
            public virtual void displayName()
            {
                Console.WriteLine("DerivedClass");
            }     
        }
    
        public class SubDerivedClass:DerivedClass
        {
            public override void displayName()
            {
                Console.WriteLine("SubDerivedClass");
            }   
        }
    
        public class SuperDerivedClass:SubDerivedClass
        {
            public void displayName()
            {
                Console.WriteLine("SuperDerivedClass");
            }     
        }
    
    
        class Program
        {
            static void Main(string[] args)
            {
                SuperDerivedClass superDerivedClass = new SuperDerivedClass();
                SubDerivedClass subDerivedClass = superDerivedClass;
                DerivedClass derivedClass = superDerivedClass;
                BaseClass baseClass = superDerivedClass;
    
                superDerivedClass.displayName();
                subDerivedClass.displayName();
                derivedClass.displayName();
                baseClass.displayName();
    
            }
        }

    执行结果

    clip_image001

    结果剖析:

    superDerivedClass.displayName();

    clip_image002 

    不需解释。没有子类,所以无多态。

     

    subDerivedClass.displayName();

    clip_image003

    subDerivedClass重写了DerivedClass的方法,则subDerivedClass中的displayName也是虚方法,于是运行时要从继承链中尽量找派生得最远的虚方法,发现其子类SuperDerivedClass没有用override,这意味着SuperDerivedClass只是覆盖了displayName方法,没有重写它。所以并不执行SuperDerivedClass的displayName,而执subDerivedClass的displayName。

    derivedClass.displayName();

    clip_image004

    DerivedClass覆盖了(是覆盖,不是重写,因为没有override标签)BaseClass的方法,但这个覆盖的方法被声明为virtual,于是运行时要从继承链中尽量找派生得最远的虚方法,发现其子类SubDerivedClass重写了这个方法,于是从SubDerivedClass继续往下找,找到SuperDerivedClass时,发现SuperDerivedClass覆盖了这个方法,没有重写,所以最终执行SubDerivedClass的displayName方法。

    baseClass.displayName();

    clip_image005

    在BaseClass中displayName是个虚方法,于是它要试图找派生的最远的虚方法。但找到DerivedClass就发现,DerivedClass已经把displayName覆盖了,这条虚链于是就断了。所以就直接执行BaseClass的方法了。

    注意:

    如果把SubDerivedClass的override去掉,则试图在SuperDerivedClass中写public override void displayName()是编译不过的。因为虽然在DerivedClass中有虚的displayName可供子类override,但由于SubDerivedClass中的DerivedClass没有加override,这相当于SubDerivedClass覆盖了DerivedClass的displayName方法,而非override了它,于是在SuperDerivedClass看到的displayName,其实是SubDerivedClass的dislayName,是一个非虚的方法,而不是从DerivedClass传承下来的虚方法,所以不能override

     

    总结

    若一个类中有一个方法,则只在两种情况下该方法才会是一个虚方法。

    1:该方法用virtual定义。

    2:该类的父类中有一个同名的虚方法,在该类中用override关键字重写了父类的虚方法。

     

    子类要想“重写”而非“覆盖”父类的方法,要满足两个条件。

    一:“父类方法是虚方法。(这意味着该方法或者是有virtual标记的,或者是override它的父类的。)”。

    二:“子类中有override标记”。

    这二者缺一,则意味着子类是对父类的方法进行了“覆盖”,而非“重写”。

     

    如果一个方法是虚方法(),则运行时从找那个“重写”得最远的方法来执行。一旦遇到“覆盖”,则继承链就断掉了。

    6月23日新增内容

    多态与abstract关键字

    abstract方法默认是虚方法,子类必须显式地用override关键字来重写。并且子类中override的方法也默认为虚方法,可以供其他类进行重写

     

    例子

    using System;
    
    public abstract class Father
    {
        public abstract void doWork();
    }
    
    public class Child : Father
    {
        public override void doWork()//该方法是虚方法,可供子类重写
        {
            Console.WriteLine("This is Child");
        }
    }
    
    public class GrandChild : Child
    {
        public override void doWork()//该方法是虚方法,可供子类重写
        {
            Console.WriteLine("This is grandChild~");
        }
    }
    
    public class M
    {
        public static void Main()
        {
            Father f = new GrandChild();
            f.doWork();
        }
    }
    

    由于多态的机制,运行结果是“This is grandChild~”

    接口与多态

    与接口有关的多态则不太适合上述分析方法。上述分析只对纯类之间的多态有效。

    接口中的方法被默认编译为virtual的,而在接口的实现类中所实现的方法,也被默认编译为override的。但在接口的实现类中所实现的方法并不能显示地使用override关键字,也并不像类中override的方法那样自动成为虚方法,若要想让该方法为虚,需要显式加上virtual。

     

    例子:

    using System;
    
    public class Father : MyInterface
    {
        public void doWork()
        {
            Console.WriteLine("Father");
        }
    }
    
    public interface MyInterface
    {
        void doWork();
    }
    
    public class Child : Father
    {
        public void doWork()
        {
            Console.WriteLine("Child");
        }
    }
    
    public class M
    {
        public static void Main()
        {
            MyInterface f = new Child();
            f.doWork();
        }
    }
    

    运行结果是 “Father”。

     

    剖析:

    以接口的身份来调用函数,却调用到了Father.doWork(),说明多态的机制生效了。但由于Father.doWork()并不默认为虚方法,所以Child并不能override这个方法,只能覆盖Father.doWork()方法,试图在Child.doWork()前边添 加override关键字会编译不过。

     

    如果在Father.doWork()前添加virtual关键字并在Child.doWork()前添加override关键字,则运行结果就变成了Child,说明从接口发出的虚链,可以无限延伸,而不是只延伸到实现接口的那个类。

  • 相关阅读:
    【SHOI2002】百事世界杯之旅
    【LGOJ 3384】树链剖分
    [20191006机房测试] 括号序列
    [20191006机房测试] 矿石
    【SHOI2012】回家的路
    [20191005机房测试] Seat
    [20191005机房测试] Silhouette
    每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样
    fgets函数读取最后一行的时候为什么会重复
    c语言中返回的变量地址,其物理地址在?(刨根问底)
  • 原文地址:https://www.cnblogs.com/ybwang/p/1755107.html
Copyright © 2011-2022 走看看