zoukankan      html  css  js  c++  java
  • C#继承

    一.继承的类型
      在面向对象的编程中,有两种截然不同继承类型:实现继承和接口继承
      1.实现继承和接口继承
      *实现继承:表示一个类型派生于基类型,它拥有该基类型的所有成员字段和函数。在实现继承中,派生类型采用基类型的每个函数的实现代码,除非在派生类型的定义中指定某个函数的实现代码。在需要给现有的类型添加功能,或许多相关的类型共享一组重要的公共功能时,可以使用这种类型的继承。
      *接口继承:表示一个类型只继承了函数的签名,没有继承任何的代码。在需要指定该类型具有某些可用的特性时,最好使用这种类型的继承。
      2.多重继承
      C#不支持多重继承,但C#允许类型派生自多个接口————多重接口继承。这说明,C#类可以派生自另一个类和任意多个接口。更准确的说,因为System.Object是一个公共的基类,所以每个C#(除Object之外)都有一个基类,还可以有任意多个接口。
      3.结构的继承
      使用结构的一个限制是结构不支持实现继承,但每个结构都自动派生自System.ValueType。不能编码实现类型层次的结构,但结构可以实现接口。

    二.继承的实现
      语法:
      class MyDreved:BaseClass
      {

      }
      如果类或结构也派生自接口,则用逗号分隔列表中的基类和接口:
      class MyDreved:BaseClass,IIntenface1,IIntenface2
      {

      }

      如果在类定义中没有指定基类,C#编译器就假定System.Object是基类。

      1.虚方法
      把一个基类函数声明为virtual,就可以在任何派生类中重写(override)该函数:
      class BaseClass
      {
        public virtual void VirtualMethod()
        {
          //
        }
      }

      也可以把属性声明为virtual。对于虚属性或重写属性,语法与非虚属性相同,但要在定义中添加virtual关键字:
      public virtual string Name
      {
        get;set;
      }

      C#中虚函数的概念与标准OOP的概念相同:可以在派生类中重写虚函数。在调用方法时,会调用该派生类的合适方法。在C#中,函数默认情况下不是虚的,但(除了构造函数)可以显式的声明为virtual。
      在派生类中重写一个函数时,要使用override关键字显示声明:
      class MyDreved: BaseClass
      {
        public override void VirtualMethod()
        {
          //
        }
      }

      成员字段和静态函数都不能声明为virtual,因为这个概念只对类中的实例函数成员有意义。

      2.隐藏方法
      如果签名相同的方法在基类和派生类中都进行了声明,但该方法没有分别声明为virtual和override,派生类方法就会隐藏基类方法。

    class A 
    {
        public void a()
        {
          Console.WriteLine('CLASS is A');
        } 
    }
    
    class B:A
    {
        public void a()
        {
           Console.WriteLine('CLASS is B');
        }
    }
    
    class client 
    {
        static void main()
        {
            B b=new B();
           A a=b;
    
           a.a();
              b.a();
        }
    }
    
    /*输出
    CLASS IS A
    CLASS IS B
    */

      在大多数情况下,是要重写方法,而不是隐藏方法,因为隐藏方法会造成对于给定类的实例调用错误的方法。但是,C#语法会在编译时收到这个潜在错误的警告。

      在C#中,要隐藏一个方法应使用new 关键字声明,这样在编译时就不会发出警告:
      class A
      {
        public void a()
        {
          Console.WriteLine('CLASS is A');
        }
      }

      class B:A
      {
        public new void a()
        {
           Console.WriteLine('CLASS is B');
        }
      }

      

      这里涉及到重写的方式(先不涉及抽象的概念):
      virtual-override方式:
      基类中被标识为virtual的方法其引用地址是程序在运行时才确定的,当父类访问子类时,如果子类中以override的方式重写了父类中的虚方法,

      这时虚方法的实际地址便指向被override覆盖的方法;
      -new方式:重写基类中的方法(包括虚方法),只有当本类被实例化时才会覆盖父类的方法。


      3.调用函数的基类版本
      C#可以从派生类中调用方法的基本版本:base.<MethodName>()
      class MyDreved: BaseClass
      {
        public override void VirtualMethod()
        {
          base.VirtualMethod();
        }
      }
      可以使用base.<MethodName>()语法调用基类中的任何方法,不必从同一方法的重载中调用它。

      4.抽象类和抽象函数
      C#允许把类和函数声明为abstract.抽象类不能实例化,而抽象抽象不能直接实现,必须在非抽象的派生类中重写。显然抽象函数也是虚拟的(尽管不需要提供virtual,实际上,也不能提供该关键字)。
      如果类包含抽象函数,则该类也是抽象的,也必须声明为抽象的:
      abstract class Building
      {
        public abstract void Cal();
      }

      抽象类中可以不含抽象方法和虚方法。

      5.密封类和密封方法
      C#允许把类和方法声明为sealed。对于类,这表示不能继承该类;对于方法,表示不能重写该方法。
      sealed class A
      {

      }

      class B:A //报错
      {

      }

      如果基类上不希望有重写的方法和属性,就不要把它声明为virtual.

      6.派生类的构造函数
      假定没有为任何类定义任何显示的构造函数,编译器就会为所有的类提供默认的初始化构造函数,在后台编译器可以很好的解决类的层次结构中的问题,每个类中的每个字段都会初始化为对应的默认值。
      在创建派生类的实例时,实际上会有多个构造函数起作用。要实例化的类的构造函数本身不能初始化类,还必须调用基类中的构造函数。
      构造函数的调用顺序是先调用Object,在按照层次结构调用基类的构造函数,由基类到父类,直到到达要实例化的类为止。在这个过程中,每个构造函数都初始化它自己的类中的字段。因为最先调用的总是基类的构造函数,所以派生类在执行过程中可以访问任何基类的成员,因为基类已经构造出来了,其字段也初始化了。

      *在层次结构中添加无参数的构造函数
        在层次结构中添加一个无参数的构造函数会替换默认的构造函数,所以在执行过程中,会默认调用基类中添加的无参数的构造函数。其它方面不变。
      *在层次结构中添加带参数的构造函数
      在层次结构中要调用这个带参数的构造函数,需要在父类的构造函数中显示调用:

    public abstract class GenericCustomer
    {
        private string name;
    
        public GenericCustomer()
        {
            name = "<no name>";
        }
    
        public GenericCustomer(string name)
        {
            this.name = name;
        }
    
    
        public string Name 
        { 
            get {return name;}
            set {name = value;}
        }
    
    }
    
    public class Nevermore60Customer : GenericCustomer
    {
        private string referrerName;
        private uint highCostMinutesUsed;
    
        ublic Nevermore60Customer(string name) : this(name, "            <None>")
        {
        }
    
        public Nevermore60Customer(string name, string referrerName) : base(name)
        {
            this.referrerName = referrerName;
        }
    
        public string ReferrerName
        {
            get {return referrerName;}
             set {referrerName = value;}
        }
    
    }    

    三. 修饰符
      修饰符可以指定方法的可见性:如public或private,还可以指定一项的本质,如方法是virtual或abstract.
      1.可见性修饰符
      修饰符            应用于                    说明
      public              所有类和成员                任何代码可以访问
      protected           类的成员和内嵌类              只有在类内部和派生类中访问
      internal           所有类和成员                只有在类内部和包含它的程序集中访问
      private          类的成员和内嵌类              只有在类内部访问
      protected internal    类的成员和内嵌类              只有在类内部,派生类中和包含它的程序集中访问

      不能把类定义为protected,private,protected internal,因为这些修饰符对于包含在名称空间中的类型没有意义。因此这些修饰符只能应用于成员。但是可以用这些修饰符定义嵌套的类(内嵌类,包含在其它类中的类),因为在这种情况下,类也具有成员的状态:
      public class OuterClass
      {
        protected class InnerClass
        {

        }
      }

      2.其它修饰符
      修饰符      应用于       说明
      new        函数        隐藏函数
      static      所有成员      静态
      virtual     函数         成员可以由派生类重写
      abstract      类,函数      抽象
      override      函数          重写虚拟和抽象的成员
      sealed      类,方法,属性       不能继承和重写
      extern        仅静态方法     成员在外部用另一种语言实现

    四.接口
      public interface IDisposable
      {
        void Dispose();
      }

      声明接口在语法上和声明抽象类完全相同,但不允许提供任何成员的实现方式。抽象类可以提供除方法之外的其它成员的实现方式,比如属性。
      一般情况下,接口只能包含方法,属性,索引器和事件的声明。
      不能实例化接口,接口即不能有构造函数,也不能有字段。接口定义也不允许包含运算符重载。
      在接口中不允许声明关于成员的修饰符。接口成员总是公有的,不能声明为虚拟和静态。如果需要,在实现的类中声明。

      实现接口的类必须实现接口的所有成员。
      接口可以彼此继承,其方式与类的继承方式相同。

  • 相关阅读:
    程序员创业第二步:五个角度打造企业世界级竞争力
    开源题材征集 + MVC&EF Core 完整教程小结
    MVC+EF Core 完整教程20--tag helper详解
    MVC5+EF6 入门完整教程13 -- 动态生成多级菜单
    加载驱动三种的方法
    Caused by: javax.el.PropertyNotFoundException: Property [userName] not found on type [java.lang.String]
    Eclipse 中的 insert spaces for tabs 设置方法
    Windows中mysql的配置文件,解决字符集编码问题,统一使用utf8字符集
    ERROR 1055 (42000): Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggregated ......问题报错解决办法!
    Java中的类三种类加载器+双气委派模型
  • 原文地址:https://www.cnblogs.com/linybo/p/13947752.html
Copyright © 2011-2022 走看看