• c# 的继承,继承类实例化的时候,会先调用基类的构造函数,然后再调用自己的构造函数,base 的用法,有override和没有override的区别


    首先举个例子:

    运行结果是

    image

    namespace 继承
    {
       
    class Program
       
    {
           
    static void Main(string[] args)
            {
               

               
    China joey = new China();           //第一个中国人,首先会调用People的无参构造函数,然后再调用China类自己的无参构造函数


               
    China lidashu = new China(2);        //如果在 China 类的带1个参数的构造函数 后面 没写base,则先调用People的无参构造函数,然后是China的有参 。
                //如果有写 base ,则先调用 People的带参数的构造函数,再是China的有参
                                                       
                                                                       
               
    China xiaoming = new China("小明", 3); 
            }
        }

       
    class People
       
    {
           
    public People()  //父类的无参构造函数
           
    {
               
    Console.WriteLine("默认的无参构造函数");
            }
           
    public People(int i)
            {
               
    Console.WriteLine("People带1个参数的构造函数");
            }
          
        }

       
    class China : People   
       
    {
           
    public China()//等价于  public China():base()   表示这个China的无参构造函数 会隐式调用 People()这个无参数的构造函数
           
    {
               
    Console.WriteLine("创建了一个中国人");
            }
           
    public China(int num)
           
    //: base(num)        //如果这里有写 base(num)  则调用People类的 People(int i) 这个构造函数,如果没有写base,那么还是 隐式调用People()这个无参数的构造函数
           
    {
               
    Console.WriteLine(num + "个中国人");
            }



           
    public China(string name, int num): base(num)   //虽然China子类的构造参数的个数同People父类不一样,但是没关系,一样可以传值到父类进行调用父类的构造参数
                                                             //至于是调用父类的哪个构造参数,就要看这里的 base 后面有几个参数,并且要看传入的是什么值类型
           
    {
               
    Console.WriteLine(num + "个中国人,名字是" + name);
            }
        }
    }

    结论:

    1:继承的写法     用冒号 :  来表示继承    (接口也是用 冒号 :  来表示的,这个要注意)。子类是调用父类的构造函数,而不是继承了父类的构造函数.

    2:  如果子类,在写构造参数的时候,如果没有写 :base()   则是隐式的调用父类的 无参数的构造函数(如果父类没有无参数的构造函数,则什么都不干,如果父类,只有带参数的构造函数,而没有无参数的构造函数,则子类在写构造函数的时候,必须写 base(num),这是因为,父类已经没有无参的构造函数了,但是子类总是会调用A的构造参数的,这个时候我们的父类没有无参构造函数,所以你子类必须显式的来用base来告诉是调用父类的哪个有参。如果父类根本就没有构造函数,则子类就无所谓了,因为此时相当于父类是有一个空的无参构造函数)

                                                      如果有写 base  ,则根据 base 后面的挂号里面的参数来调用父类的构造参数,例如  base()  这个是调用父类默认的无参构造,如果是 base(j) ,则是父类的1个参数的构造参数

    3:特殊的情况,子类的构造参数,有多个参数,例如   public China(string name, int num): base(num)   ,这个表示 子类有2个参数,调用父类的一个带参的构造函数,也就是说,调用父类多少个构造参数,是由后面的base挂号里面的参数来决定的,如果是base() 或者没有写,就是调用父类默认的无参构造函数。如果是多个,则匹配父类同样个数的有参构造函数

    如果子类里面,有自带的字段呢?


    namespace
    继承
    {
       
    class Program
       
    {
           
    static void Main(string[] args)
            {
               
    B b = new B();
               
    //这个运行的结果是 打印下面的2行
                //x=1,y=0
                //x=1,y=-1
           
    }
        }
       
    class A
       
    {
           
    public A()
            {
                PrintFields(); 
    //步骤2:在调用A的构造的时候,因为这是个虚方法,而且子类又用 override 进行了重写,所以会去调用子类的 override 方法
           
    }
           
    public virtual void PrintFields() { }
        }
       
    class B : A
       
    {
           
    int x = 1;
           
    int y;            //步骤1:在b实例化的时候,会先运行 x=1,y=0的赋值,然后开始执行B的构造的时候,先去调用A的默认构造
           
    public B()     //步骤4: 父类的构造函数完成之后,开始子类的构造方法,执行这个输出语句
           
    {
                y = -1;
               
    Console.WriteLine("x={0},y={1}", x, y);
            }
           
    public override void PrintFields()  //步骤3 :  运行这个方法
           
    {
               
    Console.WriteLine("x={0},y={1}", x, y);
            }

        }
    }

    4:如果子类有字段,那么会先给字段赋值,再执行构造函数

    5:如果父类有 virtual 函数,但是子类 没有写  override 来进行重写的话,那么子类这个函数是不执行的。(父类的会执行,但是子类不执行)

    例如

    class Program
        {
            static void Main(string[] args)
            {
                B b = new B();
                //这个运行的结果是 打印下面的1行 
                //x=1,y=-1
            }
        }
        class A
        {
            public A()
            {
                PrintFields();  //2:在调用A的构造的时候,虽然这是个虚方法,但是子类没有写 override 进行重写,所以不执行子类
            }
            public virtual void PrintFields() { }   //3:因为子类没有 override ,所以不执行子类的重写,而是会运行这里的空的函数
        }
        class B : A
        {
            int x = 1;
            int y;         //1:在b实例化的时候,会先运行 x=1,y=0的赋值,然后开始执行B的构造的时候,先去调用A的默认构造
            public B()     //4: 父类的构造函数完成之后,开始子类的构造方法,执行这个输出语句
            {
                y = -1;
                Console.WriteLine("x={0},y={1}", x, y);
            }
            public  void PrintFields()  //因为这里没有写 override 所以这个函数从头到尾压根都没有执行··
            {
                Console.WriteLine("x={0},y={1}", x, y);
            }
    
        }

    关于base的用法

    –1.调用父类中非私有的成员(调用成员,父类),  base点不出子类独有成员。

    –2.调用父类中的构造函数(调用构造函数,父类)

    •当调用从父类中继承过来的成员的时候,如果子类没有重写则this.成员;那么this.成员与base.成员,没有区别,都是指的父类的成员。

    如果子类重写了父类成员,则this.成员;调用的是子类重写以后的成员。   而base.成员;调用的依然是父类的成员。

    •子类构造函数默认调用父类的无参构造函数;

    •如果父类没有无参构造函数,则必须指明调用父类哪个构造函数

  • 相关阅读:
    在SQL Server通过DBLINK执行ORACLE存储过程
    WIFI无线网卡全双工
    ORACLE判断日期、时间的字符串是否有效日期、时间
    FN_SPLIT-表值函数, 将字符串转列表
    EBS-从职责到报表名
    LeetCode 791 自定义字符串排序
    cgit——github快速下载器
    Ubuntu 16.04下使用git clone时报“gnutls_handshake() failed: Error in the pull function”错误
    LeetCode 1702 修改后的最大二进制字符串
    一个因编码习惯不正确而产生的BUG
  • 原文地址:https://www.cnblogs.com/iceicebaby/p/2534868.html
Copyright © 2020-2023  润新知