C#基础巩固——构造函数相关

6 篇文章 0 订阅

一、C#构造函数调用顺序

定义基类MyBase,定义派生类MyDerived继承自MyBase。

    //定义基类

    class MyBase

    {

        private string name;        //基类字段

    }

    //定义派生类

    class MyDerived :MyBase

    {

        private int age;         //派生类字段

    }

这里未填写构造函数,在实例化时会生成默认构造函数,默认构造函数均用public修饰,无参数。默认构造函数会对类中的变量使用默认值进行实例化(int型字段会初始为0,string类型字段会初始为null)。在实例化MyDerived时首先会调用基类构造函数,然后调用派生类构造函数。另外C#中所有类默认派生自System.Object。

所以这里的调用顺序是:

System.Object();

MyBase();

MyDerived();

 

二、使用自定义的构造函数

1.自定义无参构造函数

这里基类使用自定义无参数的构造函数,将基类字段name初始化为“”,并在基类构造函数中输出一句话。派生类依然不填写构造函数,使用生成的默认构造函数

    //定义基类

    class MyBase

    {

        private string name;        //基类字段

        public MyBase()

        {

            name = "";

            Console.WriteLine("这是基类的构造函数");

        }

    }

 

    //定义派生类

    class MyDerived :MyBase

    {

        private int age;         //派生类字段

    }

输出结果:这是基类的构造函数。

分析总结:此时调用顺序依然是先基类构造函数,这里会使用自定义的构造函数。派生类中依然使用默认构造函数。

 

2.修改基类构造函数

在这里如果将基类修改为如下形式将会在派生类产生一个错误。

(1)构造函数声明为private

    class MyBase

    {

        private string name;        //基类字段

        private MyBase()

        {

            name = "";

            Console.WriteLine("这是基类的构造函数");

        }

错误:“MyBase.MyBase()”不可访问,因为它具有一定的保护级别

(2)构造函数带有参数

    class MyBase

    {

        private string name;        //基类字段

        public MyBase(string name)

        {

            name = "";

            Console.WriteLine("这是基类的构造函数");

        }

}

错误:未提供与“MyBase.MyBase(string)的必须形参“name对应的实参

分析总结:这些错误说明编译器在为派生类生成默认构造函数的时候,需要使用基类构造函数,并且该基类必须存在public修饰的的且无参数的构造函数。

 

3.自定义带参数的构造函数

    class MyBase

    {

        private string name;        //基类字段

        public MyBase(string name)        //带有参数的基类构造函数

        {

            this.name =name ;

            Console.WriteLine("这是基类的构造函数");

        }

    }


以下的写法均会产生错误:

(1)使用系统提供的默认构造函数

    class MyDerived :MyBase

    {

        private int age;         //派生类字段

}

(2)自定义无参构造函数

    class MyDerived :MyBase

    {

        private int age;         //派生类字段

        public MyDerived()

        {

            age = 0;

            Console.WriteLine("这是派生类的构造函数");

        }

}

(3)定义有参数构造函数,但未向基类传递参数

    class MyDerived :MyBase

    {

        private int age;         //派生类字段

        public MyDerived(string name)

        {

            age = 0;

            Console.WriteLine("这是派生类的构造函数");

        }

}

(4)存在多个构造函数,但部分构造函数未向基类传递参数

    class MyDerived :MyBase

    {

        private int age;         //派生类字段

        public MyDerived()

        {

            age = 0;

            Console.WriteLine("这是派生类的构造函数");

        }

        public MyDerived(string name) : base(name)

        {

            age = 0;

            Console.WriteLine("这是派生类的构造函数");

        }

    }

以上四种情况会产生的相同的错误:未提供与“MyBase.MyBase(string)”的必需形参“name”对应的实参第四种错误提示在无参构造函数MyDerived()上

 

正确的写法:

(1)通过派生类的构造函数传递可变的参数到基类构造函数

    class MyDerived :MyBase

    {

        private int age;         //派生类字段

        public MyDerived(string name) : base(name)

        {

            age = 0;

            Console.WriteLine("这是派生类的构造函数");

        } }

(2)在派生类构造函数后添加base(“aaa”)传入固定的参数

    class MyDerived :MyBase

    {

        private int age;         //派生类字段

        public MyDerived():base("aaa")

        {

            age = 0;

            Console.WriteLine("这是派生类的构造函数");

        }

    }

分析总结:如果基类中使用了带参数构造函数时,并且只有这样一个构造函数,那么我们在派生类中必须使用自定义的构造函数,并且使用base()向基类的构造函数传递参数。在这两种写法中第一种可以在派生类实例化时传入参数,并将该参数传递到基类。第二种则可以写在任意派生类构造函数后,将默认的值传到基类构造函数中。

    //定义基类

    class MyBase

    {

        private string name;        //基类字段

        public MyBase(string name)

        {

            this.name =name ;

            Console.WriteLine("这是基类的构造函数"+name);

        }

    }

 

    //定义派生类

    class MyDerived :MyBase

    {

        private int age;         //派生类字段

        public MyDerived():base("aaa")

        {

            age = 0;

            Console.WriteLine("这是派生类的构造函数");

        }

        public MyDerived(string name) : base(name)

        {

            age = 0;

            Console.WriteLine("这是派生类的构造函数");

        }

    }

 

    class Program

    {

        static void Main(string[] args)

        {

            MyDerived test = new MyDerived();

            MyDerived test2 = new MyDerived("bbb");

        }

    }

 

执行结果:

这是基类的构造函数aaa

这是派生类的构造函数

这是基类的构造函数bbb

这是派生类的构造函数

 

三、构造函数中的this和base关键字

this和base均为构造函数后使用的关键字,他们的语法基本相同,均为写在构造函数后面。

修饰符   构造函数名()  :   this/base([参数1],[参数2]...)。

this先执行this指向的构造函数,执行完成后执行当前的构造函数。base表示先执行基类的构造函数,执行完成后执行本构造函数。如果具有多个构造函数,this和base执行的内容根据后面所指定的参数决定。

//定义基类

    class MyBase

    {

        private string name;        //基类字段

        public MyBase(string name)         

        {

            this.name = name;

            Console.WriteLine("这是基类的带参数的构造函数,name is:" + name);

        }

        public MyBase()

        {

            Console.WriteLine("这是基类的无参数的构造函数");

        }

    }

 

    //定义派生类

    class MyDerived : MyBase

    {

        private int age;         //派生类字段    

        public MyDerived(string name) : base(name)      //先调用基类的一个参数的构造函数,传入name

        {

            Console.WriteLine("这是派生类的一个参数的构造函数,向基类传递参数name");

        }

        public MyDerived(string name,int age) : this(name)              //先执行本类的无参构造函数

        {

            this.age = age;

            Console.WriteLine("这是派生类的有两个参数的构造函数,传入参数name和age,age is:"+age);

        }

}

 

    class Program

    {

        static void Main(string[] args)

        {

            MyDerived test = new MyDerived("AAA",18);

        }

    }

在这里进行实例化时首先会进入派生类两个参数的构造函数,派生类进入后会优先执行this指向的一个参数的构造函数,此时会先调用基类的含有一个参数的构造函数。

执行结果:

这是基类的带参数的构造函数,name is:AAA

这是派生类的一个参数的构造函数,向基类传递参数name

这是派生类的有两个参数的构造函数,传入参数name和age,age is:18

 

 

namespace baseknowledge

{

    //定义基类

    class MyBase

    {

        private string name;        //基类字段

        public MyBase(string name)        

        {

            this.name = name;

            Console.WriteLine("这是基类的带参数的构造函数,name is:" + name);

        }

        public MyBase()

        {

            Console.WriteLine("这是基类的无参数的构造函数");

        }

    }

 

    //定义派生类

    class MyDerived : MyBase

    {

        private int age;         //派生类字段    

        public MyDerived(string name)     

        {

            Console.WriteLine("这是派生类的一个参数的构造函数");

        }

        public MyDerived(string name, int age) : this(name)              //先执行本类的无参构造函数

        {

            this.age = age;

            Console.WriteLine("这是派生类的有两个参数的构造函数,传入参数name和age,age is:" + age);

        }

    }

 

 

    class Program

    {

        static void Main(string[] args)

        {

            MyDerived test = new MyDerived("AAA", 18);

        }

    }

}

这里在派生类中没有指定需要执行构造函数,那么首先会执行基类没有参数的构造函数。然后执行派生类两个参数的构造函数后this指定的一个参数的构造函数,最后执行两个参数的构造函数。

执行结果:

这是基类的无参数的构造函数

这是派生类的一个参数的构造函数

这是派生类的有两个参数的构造函数,传入参数name和age,age is:18

 

分析总结:通过以上两段代码可以发现,执行派生类的构造函数时首先执行基类的构造函数,如果存在base指定的基类构造函数,执行指定的构造函数,没有则执行默认的构造函数。执行结束后执行派生类构造函数。同时this和base指定的构造函数在当前构造函数之前执行。

 

 

 

 

 

 

 

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值