• c#之继承


    一:继承的分类
    从c#中的继承可以分为两种(其他面向对象的语言貌似也是这样)
    实现继承(不能实现多重继承,子类只能从一个父类派生)
    接口继承(可以从多个接口派生)
    结构是值类型的,不支持实现继承,支持接口继承,可以派生于多个接口

    二:修饰符

    public 任何代码均可访问
    protected 仅派生类型可访问,实例对象不可访问
    internal 程序集内部可访问
    private 只能在类内部访问
    protected internal 程序集内部派生类中
    new 用相同的签名覆盖基类中的成员
    static 成员不在类的具体实例上执行
    virtual 成员可以由派生类重写
    abstract 只定义成员的签名,没有实现代码
    override 该成员重写了基类中的相同签名的virtual成员,并允许被再次重写
    sealed 该成员重写了基类中的相同签名的virtual成员,并不允许被再次重写

    三:
    子类拥有父类的所有子类可见成员
    这也是设计子类的目的之一,为了扩展父类的功能

    四:重写
    方法只要声明为virtual,就可以被子类中签名相同的方法重写(override)
    当然子类也可以不重写这个方法
    成员字段和静态函数都不能被声明为virtual
    一个方法被修饰成override,这个方法仍旧可以被它的子类重写

    五:覆盖
    用new关键字可以隐藏基类的方法,字段
    这个感觉没什么好说的

    综合例子一(看输出结果之前,希望你能仔细想以想)

        public class baseClass
        {
            public void Methord()
            {
                Console.WriteLine("methord from base");
            }
            public virtual void Methord2()
            {
                Console.WriteLine("virtual methord from base");
            }
        }
        public class sonClass : baseClass
        {
            public new void Methord()
            {
                Console.WriteLine("methord form son");
            }
            public override void Methord2()
            {
                Console.WriteLine("override methord from son");
            }
        }
        class Program
        {
            static void Main(string[] args)
            {
                baseClass b = new baseClass();
                b.Methord();
                b.Methord2();
                Console.WriteLine();
    
                sonClass s = new sonClass();
                s.Methord();
                s.Methord2();
                Console.WriteLine();
    
                baseClass b2 = new sonClass();
                b2.Methord();
                b2.Methord2();
                Console.WriteLine();
    
                sonClass s2 = (sonClass)b2;
                s2.Methord();
                s2.Methord2();
                Console.WriteLine();
                
                Console.ReadKey();
            }
        }

    输出结果为:
    image 
    很多面试题中都有类似的题
    我做个总结
    一般情况下变量的类型是什么,该变量就拥有什么类型的成员
    即使像下面这种情况也不例外
    baseClass b2 = new sonClass();
    b2的成员是baseClass中的成员
    b2与sonClass中的成员无关
    只有一种情况除外
    当父类中的virtual方法已经被子类中的方法override过之后(new重写过之后是不行的)
    类似这种情况baseClass b2 = new sonClass();
    b2拥有的是重写过的方法成员
    具体的原理以后有机会分析一下IL代码
    那么我们总结一下这个现象
    每个类型都有自己的类型成员表,虚方法成员是动态绑定的,运行时动态覆盖

    综合例子二

        public class A
        {
            public virtual void Fun1(int i)
            {
                Console.WriteLine(i);
            }
    
            public void Fun2(A a)
            {
                a.Fun1(1);
                Fun1(5);
            }
        }
        public class B : A
        {
            public override void Fun1(int i)
            {
                base.Fun1(i + 1);
            }
    
            public static void Main()
            {
                B b = new B();
                A a = new A();
                a.Fun2(b);
                b.Fun2(a);
                Console.ReadKey();
            }
        }

    输出为
    image 
    就不多解释了

    六:通过base关键字获取基类的成员
    看个比较特殊的例子

        public class baseClass
        {
            public virtual void Methord2()
            {
                Console.WriteLine("virtual methord from base");
            }
        }
        public class sonClass : baseClass
        {
            public override void Methord2()
            {
                base.Methord2();
                Console.WriteLine("override methord from son");
            }
        }
        class Program
        {
            static void Main(string[] args)
            {
                baseClass b2 = new sonClass();
                b2.Methord2();
                
                Console.ReadKey();
            }
        }

    输出为:
    image 
    由此可见重写方法是可以通过base关键字调用被重写的方法的
    基类的成员表在重写方法中是可见的

    七:抽象类和抽象方法(abstract)
    抽象类不能实例化
    抽象方法没有执行代码
    如果类包含抽象方法,那么该类也必须声明为abstract
    当然一个声明为abstract的类可以包含实例方法
    抽象方法与虚方法类似,也是运行时动态绑定的

    八:密封类和密封方法(sealed)
    密封类不能被继承
    sealed关键字只能修饰重写(override)方法
    密封方法不能被重写
    但是可以通过new关键字覆盖它
    除非特殊情况最好少用这个关键字

    九:继承关系中的构造函数
    初始化一个类的实例的具体步骤是
    1:初始化该类的字段
    2:初始化基类的字段
    3:初始化基类的构造函数
    4:初始化该类的构造函数
    可以通过base关键字制定初始化基类中的哪个构造函数

    再看个综合例子,你觉得应该输出什么

        class A 
        { 
              public A() 
              { 
                    PrintFields(); 
              } 
              public virtual void PrintFields(){} 
          }
        class B : A
        {
            int x = 1;
            int y;
            public B()
            {
                y = -1;
                PrintFields();
            }
            public override void PrintFields()
            {
                Console.WriteLine("x={0},y={1}", x, y);
            }
        }
        class Program
        {
            static void Main(string[] args)
            {
                A b = new B();
                Console.ReadKey();
            }
        }

    输出为:
    image 
    就不多解释了

    十:接口继承
    接口继承和实现继承其实差不多
    做几点说明:
    1.一个类可以实现多个接口
    2.不允许提供接口中任何成员的实现方式
    3.接口只能包含方法,属性,所引器和事件,不允许包含运算符重载
    4.不能实例化接口,因此接口不能有构造函数
    5.不能声明成员修饰符,接口成员总是公共的,也不能声明成员为虚拟的或者静态的,这些是具体实现的时候做的事情


    做此文得到了郑州的Xuefly的支持,在此表示感谢

  • 相关阅读:
    Helvetic Coding Contest 2016 online mirror D1
    Helvetic Coding Contest 2016 online mirror C1
    Helvetic Coding Contest 2016 online mirror A1
    Educational Codeforces Round 13 C
    Educational Codeforces Round 13 B
    Educational Codeforces Round 13 A
    2016计蒜之道初赛第四场A
    帆软出品: 7点搞定制药企业数据分析系统开发需求
    制药企业BI系统方案整体设计分享
    Ubuntu ROS Arduino Gazebo学习镜像iso说明(indigo版)
  • 原文地址:https://www.cnblogs.com/liulun/p/1491588.html
Copyright © 2020-2023  润新知