继承
在前面我们学习了如何去定义类,用类当做模板来声明我们的数据。那么当我们的程序需要很多个类,但是这些类有很多相似的字段和方法,我们也要一个个重新去定义吗?
我们可以使用继承,将相同的方法和字段放在一个基类里,有不同的字段或方法就写在派生类,继承基类。
这里有个概念,派生类即子类,基类即父类,这两种说法都正确。
实现继承
表示一个类型派生于一个基类,它拥有该基类的所有成员字段和函数。在实现继承中,派生类型采用基类的每个函数的实现代码,除非在派生类的定义中指定重写某个函数的实现代码(后面会讲到如何重写)。
在有需要给现有类型添加功能,或者许多相关类型共享一组重要公共功能,这种类型的继承非常有用。
接口继承
表示一个类型只继承了函数的签名,没有继承任何实现代码。在需要指定该类型具有某些可用的特性时,最好使用这种类型的继承。(接口继承在这篇文章不详细说明)
多重继承
一些语言(C++)支持多重继承,即一个类派生自多个类。
多重继承可以编写非常复杂但是很紧凑的代码,但是多重继承的代码常常很难理解和调试。
C#不支持多重继承,但是支持类型派生于多个接口——多重接口继承。
这说明C#类可以派生自另一个类和任意多个接口,更准确的来说:System.Object是一个公共的基类,所以每个C#(除了Object类之外)都有一个基类,还可以有任意多个接口。
继承的语法规则
如果要声明派生另一个类的一个类,可以使用下面的语法
class MyDerivedClass:MyBaseClass{
//function and data members here
}
其中,MyBaseClass就是基类,MyDerivedClass是子类,子类和基类用冒号隔开,实现了继承。
如果类(或结构)也派生自接口,则用逗号分隔
public class MyDerivedClass:MyBaseClass,IInterface1,IInterface2{
//code
}
下面是一段继承代码的实例。
class Enemy
{
private float hp;
private float speed;
public float HP
{
get { return hp; }
set { hp = value; }
}
public float Speed
{
get { return speed; }
set { speed = value; }
}
public void AI()
{
Move();
Console.WriteLine("这里是基类的AI");
}
public void Move()
{
Console.WriteLine("这里是基类在移动");
}
}
class Boss:Enemy
{
public void Attack()
{
AI();
Move();
HP = 100;//父类里共有的数据成员和函数成员才可以在子类里访问
Console.WriteLine("该BOSS正在攻击");
}
}
static void Main(string[] args)
{
Boss boss = new Boss();
boss.Attack();//继承,父类里的所有数据成员和函数成员都会继承到子类里
Enemy enemy;
enemy = new Boss();//父类声明的对象,可以用子类去构造,但是子类声明的对象,不能用父类去构造
//虽然enemy是用父类声明的,但是是子类构造,所以本质上是子类类型,所有我们要强制转换成子类类型才能够使用子类的方法
Boss boss = (Boss)enemy;
boss.Attack();
Enemy enemy = new Enemy();
Boss boss = (Boss)enemy; //一个对象是什么类型的,主要是看他是通过什么来构造的
//虽然IDE没有报错,但是运行程序之后会提示无法强制转换
//父类不能够强制转换成子类,因为子类的数据成员和函数成员比父类多
Console.ReadKey();
}
在这段代码中我们可以知道继承的一些特性。
- 子类只能够访问基类中公共的数据成员和函数成员
- 继承之后,子类拥有基类里所有的数据成员和函数成员
- 继承之后,我们可以用父类来声明对象,用子类来构造,但是不能用子类声明,父类构造
- 使用父类声明子类构造,所以该对象为子类类型,但是如果该对象要使用子类里的方法,需要强制转换
- 子类类型可以强制转换成父类类型,但是反之不行,因为作为子类,里面的函数成员和数据成员一般情况下都会比父类里的多。这和byte类型不能转换成int类型是一个道理。
this和base关键字
在我们实现继承之后,子类和父类会有很多相同的数据成员和函数成员,那么我们在写代码过程中如何清晰明了地看出这些成员是属于子类还是父类的呢?
使用this关键字,表明该成员是自身这个类里的成员。
使用base关键字,表明该成员是基类里的成员。
使用这两个关键字有一个好处,输入完关键字后,IDE会自动提示有哪些成员能够被调用,当程序很复杂的时候,这个功能能使我们更好的完成程序。但是不使用这两个关键字也无关紧要,不影响程序的编译和运行。