C#-继承
继承
用来解决类与类之间的代码冗余。
我们可能会在一些类中,写一些重复的成员,我们可以将这些重复的成员,单独的封装到一个类中,作为这些类的父类。如下代码:
public class Person//父类Person { private string _name; public string Name { get { return _name; } set { _name = value; } } private char _gender; public char Gender { get { return _gender; } set { _gender = value; } } private int _age; public int Age { get { return _age; } set { _age = value; } } public void CHLSS() { Console.WriteLine("CHLSS"); } public Person(string name,char gender,int age)//父类的构造函数 { this.Name = name; this.Gender = gender; this.Age = age; } } public class Studert:Person//子类Student继承于父类Person { private int _id; public int Id { get { return _id; } set { _id = value; } } public void Study() { Console.WriteLine("我会学习"); } public Studert(string name,char gender,int age,int id) :base(name,gender,age)//继承父类的构造函数 { this.Id = id; } } public class Teacher:Person//子类Teacher继承于父类Person { private decimal _salary; public decimal Salary { get { return _salary; } set { _salary = value; } } public void Teach() { Console.WriteLine("我会教书"); } public Teacher(string name,char gender,int age,decimal salary) :base(name,gender,age)//继承父类的构造函数 { this.Salary = Salary; } } public class Driver:Person//子类Driver继承于父类Person { private double _driveTime; public double DriveTime { get { return _driveTime; } set{ _driveTime = value; } } public void Drive() { Console.WriteLine("我会开车"); } public Driver(string name,char gender,int age,double driverTime) :base(name,gender,age)//继承父类的构造函数 { this.DriveTime = driverTime; } }
上面代码中,Person作为一个父类,封装了属性Name,Gender,Age,这三个属性对于Student类,Techer类以及Driver类都是服复用的;如果没有继承这个概念,Student类,Techer类,Driver类以及后续类似可能需要声明属性Name,Gender,Age的各种类来讲,都需要在各自的类里面单独声明属性Name,Gender,Age,这样程序就有大量的冗余代码。现在我们用一个名为Person的类来封装这段可能被反复重复声明的属性Name,Gender,Age,此时Person类我们称为父类(或 基类),其他类(Student、Teacher、Driver...)通过继承Person类,来继承Person类里面的所有的属性(Name,Gender,Age),而不是像以往一样单独在各自类中重复的声明属性,Student、Teacher、Driver这些继承于父类的类称为子类(或派生类)。
继承的语法:
在声明类的后面加上“:父类名”即可,代码如下:
public class Studert:Person//子类Student继承于父类Person { private int _id; public int Id { get { return _id; } set { _id = value; } } public void Study() { Console.WriteLine("我会学习"); } public Studert(string name,char gender,int age,int id) :base(name,gender,age)//继承父类的构造函数 { this.Id = id; } }
上面代码可以看出Student类继承于名为Person的父类,子类既可以继承父类的成员也可以拥有属于自己的成员。Student类中不仅有继承于Person类的属性(Name,Gender,Age)还有自己特有的属性Id和方法Study()。
剖析:
1、子类继承了父类,那么子类从父类那里继承过来了什么?
答:子类继承了父类的属性和方法,但是子类并没有继承父类的私有字段。如果希望继承父类的字段,那么父类的字段需要公有化,但是不建议此类操作。
2、子类有没有继承父类的构造函数?
答:子类并没有继承父类的构造函数。但是,子类会默认的调用父类无参数的构造函数。子类在创建对象的时候,子类会先在子类中创建父类对象,让子类可以使用父类中的成员。
所以,会出现这种情况,如果在父类中重新写了一个有参数的构造函数之后,那个默认的无参数的构造函数就会被干掉,子类就调用不到了,所以子类会报错。
出现这种情况我们要怎样解决?
方法(1)、在父类中重新写一个无参数的构造函数。
方法(2)、在子类中显示的调用父类的构造函数,使用关键字:base(),如下代码:
public class Teacher:Person//子类Teacher继承于父类Person { private decimal _salary; public decimal Salary { get { return _salary; } set { _salary = value; } } public void Teach() { Console.WriteLine("我会教书"); } public Teacher(string name,char gender,int age,decimal salary) :base(name,gender,age)//继承父类的构造函数 { this.Salary = Salary; } }
上面代码Teacher类继承于Person。Techer类的构造函数Teacher()是有参的,通过加上关键字“:base()”的操作,去调用Person类的构造函数。
继承的两个特性:
1、继承的单根性:一个子类只能有一个父类。
2、继承的传递性:一个子类可以被其他类继承,从何成为其他类的父类。
拓展:
1、可以通过查看类图来查来类的继承关系;
2、object是所有类的基类。
3、new关键字
1),创建对象
2).隐藏从父类那里继承过来的同名成员。隐藏的后果就是子类调用不到父类的成员。