在C#当中,程序员写的每一个类在没写其它构造函数的情况下,都会默认有一个无参构造函数。
代码如下:
class DemoClass { public string Name { set; get; } } DemoClass demoOb = new DemoClass();
如果程序员写了其它的构造函数,那类本身默认的无参构造函数会自动消失,所以更谈不上构造函数重载。
代码如下:
class DemoClass { public string Name { set; get; } //添加一个string类型参数列表的构造函数 public DemoClass(string strName) { this.Name = strName; } } DemoClass Demoob1 = new DemoClass("小明");//正确 DemoClass demoOb2= new DemoClass();//错误,因为原来那个默认无参构造函数已经消失
这个时候,如果还想使用无参构造函数,必须重新写一个无参构造函数
也就是所谓的函数重载问题了,在这儿一定要记住,函数重载依靠的是参数类型,不是参数名
代码如下:
class DemoClass { public string Name { set; get; } //添加一个string类型参数列表的构造函数 public DemoClass(string strName) { this.Name = strName; } //无参构造函数 public DemoClass() { Console.WriteLine("I am no Parameter Fun"); } //再添加一个构造函数演示重载 public DemoClass(string strName1, string strName2) { Console.WriteLine("Two Parameters"); } } DemoClass Demoob1 = new DemoClass("小明");//正确 DemoClass demoOb2 = new DemoClass();//正确 DemoClass demoOb3 = new DemoClass("小刘", "小李");//正确
现在讲继承当中的构造函数问题:
首先:要理解这是一个递归的过程,子类会调用父类,父类也会根据情况调用爷爷类
在不做其它操作的情况下,子类的任何不同的构造函数都会先而且必须调用父类的无参构造函数,再调用实例化中所使用的本类构造函数,如果父类之上还有爷爷类,那么就是调用顺序:爷爷类->父类->本类
代码如下:
class GrandParentClass { protected string name; public string Name { get { return name; } set { this.name = value; } } public GrandParentClass(string strName) { Console.WriteLine("GrandParentClass One parameter Constructor"); } public GrandParentClass() { Console.WriteLine("GrandClass No parameter Constructor"); } } class FatherClass :GrandParentClass { public FatherClass() { Console.WriteLine("ParentClass No parameter Constructor"); } public FatherClass(string strName) { Console.WriteLine("FatherClass One parameter Constructor"); } } class ChildClass : FatherClass { public ChildClass() { Console.WriteLine("ChildClass No parameter Constructor"); } public ChildClass(string strName) { Console.WriteLine("ChildClass One parameter Constructor"); } } //会依次调用爷爷类,父亲类的无参构造函数 最后调用实例化中使用的本类的构造函数 ChildClass childOb = new ChildClass(); Console.WriteLine("******************************"); //会依次调用爷爷类,父亲类的无参构造函数 最后调用实例化中使用的本类的构造函数 ChildClass childOb2 = new ChildClass("wang");
运行结果如下:
记住,不管使用的什么构造函数,在不做处理的情况下,都会首先调用父类的无参构造函数,如果父类没有无参构造函数,那就会无法运行。
class GrandParentClass { protected string name; public string Name { get { return name; } set { this.name = value; } } public GrandParentClass(string strName) { Console.WriteLine("GrandParentClass One parameter Constructor"); } public GrandParentClass() { Console.WriteLine("GrandClass No parameter Constructor"); } } class FatherClass :GrandParentClass { ///去掉了无参构造函数 //public FatherClass() //{ // Console.WriteLine("ParentClass No parameter Constructor"); //} public FatherClass(string strName) { Console.WriteLine("FatherClass One parameter Constructor"); } } class ChildClass : FatherClass { public ChildClass() { Console.WriteLine("ChildClass No parameter Constructor"); } public ChildClass(string strName) { Console.WriteLine("ChildClass One parameter Constructor"); } }
这样就会提示:错误 “OverNewDemo.FatherClass”不包含采用“0”个参数的构造函数 E:\OverNewDemo\OverNewDemo\Program.cs 73 16 OverNewDemo
当然:如果我们把另外那个构造函数注释掉了,就可以运行,因为FatherClass里面就没有写任何构造函数了,它会默认有一个无参构造函数。
那么如果我们真的就是想在子类当中调父类的其它构造函数呢?
方法如下:
只需要在子类构造函数后面加上 “base:(实参数)” 这样就会先调用父类对应的构造函数,括号里的实参数就会传递给父类的构造函数参数。
代码如下:
class GrandParentClass { protected string name; public string Name { get { return name; } set { this.name = value; } } public GrandParentClass(string strName) { Console.WriteLine("GrandParentClass One parameter Constructor"); } public GrandParentClass() { Console.WriteLine("GrandClass No parameter Constructor"); } } class FatherClass :GrandParentClass { public FatherClass() { Console.WriteLine("ParentClass No parameter Constructor"); } public FatherClass(string strName) { Console.WriteLine("FatherClass One parameter Constructor"); } } class ChildClass : FatherClass { public ChildClass() { Console.WriteLine("ChildClass No parameter Constructor"); } public ChildClass(string strName):base(strName) { Console.WriteLine("ChildClass One parameter Constructor"); } } ChildClass childOb2 = new ChildClass("wang");
这样就成功了,大家可以看到,子类的确调用了父类的有参构造函数,但是爷爷类还是调用的无参构造函数,这是因为这是一个递归的过程,父类的有参构造函数在不加 base的处理下,还是会调用爷爷类的有参构造函数,递归!!!这个时候把父类的无参构造函数注释掉也不会报错,因为它不会去调用,也不谈出错。
下面总结重载,重写和覆盖
1.重载很简单,就是多种不同参数列表甚至不同返回类型的同名函数,调用时依靠参数列表和参数类型进行区别, 需要注意:如果出现了相同参数列表但不同返回类型的方法,就会出错,因为不知道调用哪一个方法。
2. C# override重写,是指对父类中的虚方法(标记virtual)或抽象方法(标记为abstract)进行重写,实现新的功能,它必须与父类方法的签名完全一致,而且与父类方法的可访问性也必须一致.
注意:父类 对象名=new 父类名(); 仍然会使用原来的方法、
父类 对象名=new 子类名(); 会使用新方法
可以间接认为改动了父类方法
3.new隐藏(也叫做覆盖),是指在子类中重新定义一个签名与父类的方法相同的方法,这个方法可以不用new修饰,只是编译时会弹出一个警告信息:如果是有意隐藏,请使用关键字new。
注意:
父类 对象名=new 父类名(); 仍然会使用原来的方法、
父类 对象名=new 子类名(); 仍然会使用原来的方法、
代码如下:
class Program { static void Main(string[] args) { FatherClassd fathOb1= new FatherClassd(); fathOb1.Method1();//输出fath FatherClassd fathOb2 = new ChildClass(); fathOb2.Method1();//输出child1 FatherClassd fathOb3 = new ChildClass2(); fathOb3.Method1();//输出fath ChildClass child1 = new ChildClass(); child1.Method1();//输出child1 ChildClass2 child2 = new ChildClass2(); child2.Method1();//输出child2 Console.ReadKey(); } } class FatherClassd { public virtual void Method1() { Console.WriteLine("fath"); } } class ChildClass:FatherClassd { //重写 public override void Method1() { Console.WriteLine("child1"); } } class ChildClass2 : FatherClassd { //覆盖或者叫做隐藏 public new void Method1() { Console.WriteLine("child2"); } }