在现有类(称为基类、父类)上建立新类(称为派生类、子类)的处理过程称为继承。通俗来讲就是从父辈身上继承点特征。派生类能自动获取基类(除了构造函数和析构函数(私有成员)的所有成员),可以在派生类中添加新的属性和方法扩展其功能。
1.类使用继承时,只需要写一次代码
编写c#程序时,通常会创建一些类来表示真实世界中的事物,这些事物之间往往会存在关联。类之中之所以存在类似的代码。正是因为他们表示的真实事物有类似的行为。
2.建立类模型:从一般到特定
c#程序使用了继承,因为程序会对真实事物建模,而继承可以模仿实际事物之间的关系,真是世界中的事物往往存在于一个层次体系中,从一般到特定,相应的程序中的类层次体系也是如此。在类模型中,层次体系结构中较低的类继承自它上面的类。
▲例子:怎样设计一个动物园模拟系统?
第一步:找出动物共同的特点。
第二步:构建一个基类,提供动物共有的全部特点。(基类中的字段、属性和方法会为继承自这个基类的所有动物提供共同的状态和行为)。
第三步:找出各个动物的哪些行为与基类有所不同,或者哪些行为在基类中根本没有。
第四步:查找有共同特点的类。
第五步:完成层次体系。
3.使用继承避免子类中出现重复代码
关于重复代码的弊端你应该已经很清楚了。重复代码很难维护,而且总是让人很头疼。
4.子类改变所继承的这个某个方法行为时,我们成为它覆盖了这个方法。
5.创建类的一个链,这些类形成继承关系,从最上层的基类一直乡下继承。
6.创建类层析体系。
创建类时,最上面一个是基类,子类放在它下面,而这些子类本身又有自己的子类,此时创建的就是一个类层次体系。这就不只是能够避免重复代码了,也容易维护。
7.每个子类都扩展其基类
子类并不只是继承其基类的方法。为一个类增加继承关系时,所做的就是对已经构建的类进行扩展,为他增加基类中的所有字段、属性和方法。子类从一个基类继承时,积累中所有字段、属性和方法都会自动增加到子类。
8.使用冒号继承基类
编写一个类是,可以使用一个冒号“:”使他继承一个基类。这样这个类就成为了一个子类,并得到被继承类(基类)的所有字段、属性和方法。
▲例:
class Vertebrate
{
public int NumberOfLegs;
public void Eat()
{
//code to make it eat
}
}
class Bird:Vertrbrate
{
public double Wingspan;
public void Fly()
{
//code to make the bird fly
}
}
★问:为什么箭头向上指,从子类指向基类?如果箭头向下指,这个图不是更好看一些吗?
答:也许看上去会漂亮一些,不过这样就不正确了。建立一个类并让他继承另一个类时,会把这种关系建立在 子类中,基类仍保持原样。如果从基类的角度来考虑这一点是很有道理的。增加一个从基类继承的子类时,积累的行为完全没有变化。积累甚至不知道这个新类是从他继承的,他的方法属性字段仍保持不变。不过子类肯定会改变行为,子类的每一个实例都会自动地得到基类的所有属性、字段和方法,而所有这些只需要增加一个冒号就可以轻松得到,正是因为这个原因,图中的箭头要向上指,表示这是子类的一部分,指向所继承的基类。
9.子类可以覆盖方法来改变或替换它继承的方法。
有时你可能希望子类继承基类的大部分行为,但是并非所有行为。如果希望改变一个继承的某些行为,可以覆盖这些方法。
❶为基类中的方法添加Virtual关键字
子类只能覆盖标志由virtual关键字的方法,这就告诉c#允许子类覆盖这些方法。
class Bird
{
public *virtual* void Fly()
{
//code to make the bird fly
}
}
❷为派生类增加一个同名的方法
这个方法要有完全相同的方法签名,这说明返回值和参数都相同,而且要在声明中使用override关键字。
class Penguin:Bird
{
public override void Fly()
{
MessageBox.Show("Penguins can't fly!")
}
}
10.只要能使用基类,就可以使用它的某个子类
对于继承,最有用的一点就是可以使用子类来取他继承的基类。
★相关问题:
★1.可以继承一个包含入口点的类吗?
答:可以。入口点肯定是一个静态方法,但是这个方法不一定非得放在静态类中(static关键字表示这个类不能实例化,程序一旦运行就可以使用这个类的方法。)
★2.只能沿着类图上行而不能下行,这是什么意思?
答:类图中,如果一个类在另一个类的上面,上面的这个类就比下面的类更抽象,更特定或更具体的类从更抽象的类继承。
▲如果一个方法需要父类作为参数,则总是可以传入其子类的实例。
11.子类可以隐藏超类中的方法
如果子类只是增加一个与超类方法同名的方法,那么它只是隐藏了超类方法而不是覆盖这个方法。(隐藏方法用new关键字)
12.使用override和virtual关键字来继承行为
吃力一个扩展了一个基类的子类时,往往希望覆盖而不是隐藏,如果你想覆盖一个基类中的方法,则一定要标志virtual关键字,而且只要希望在子类中覆盖这个方法就要使用override关键字。如果没有做到这一点,则最终就会无意中隐藏方法。
13.子类可以使用base关键字访问基类
即使子类中覆盖了基类中的方法或属性,有时仍可以访问基类中的这个成员。幸运的是,可以用base关键字,利用这个关键字就可以访问基类中的任何方法。
14.如果基类有构造函数,子类也需要有构造函数
如果类有一些带参数的构造函数,继承自这个类的所有子类必须调用其中某个构造函数。子类的构造函数与基类构造函数可以有不同的参数。
利用继承,可以很容易的更新修改代码。