1.什么是继承?
在C#里,很多类有相似的数据,它们有相似的属性,也有不同的,这时我们可以用继承来让某几个类来继承同一个类。任何类都可以从另外一个类继承,这就是说,这个类拥有它继承的类的所有成员。在面向对象编程中,被继承的类叫父类或基类。所有类默认继承object基类。
2.继承的类型
a.实现继承
简单地说,就是表示一个类型派生于一个基类型,它拥有基类所有的成员字段和函数。
b.接口继承
简单地说,表示一个类型只继承了函数的签名(返回类型,方法名,参数列表),没有继承任何实现代码。
3.继承的使用
新建一个项目,添加一个Enemy类,这个类里面的字段和函数成员如下:
class Enemy
{
private int hp;
private float speed;
public int HP
{
get
{
return hp;
}
set
{
hp = value;
}
}
public float Speed { get; set; }
public void AI()
{
Console.WriteLine("是Enemy的公有的AI方法");
}
public void Move()
{
Console.WriteLine("是Enemy的公有的Move方法");
}
}
再新添加一个Boss类,让它继承自Enemy类,如下所示:
class Boss:Enemy
{
public void Attack()//子类里自己新增的方法
{
AI();
Move();
Console.WriteLine("Boss正在进行攻击");
}
}
然后在项目里创建一个名为boss的对象,如下所示:
class Program
{
static void Main(string[] args)
{
Boss boss = new Boss();
boss.Attack();//继承:父类里所有的函数成员和数据成员都会被继承到子类里
}
}
返回结果为:
是Enemy的公有的AI方法
是Enemy的公有的Move方法
Boss正在进行攻击
解释:因为boss类继承了Enemy类,所以Enemy里的函数成员会被继承,同时boss类还有自己新的函数成员Attack().
还有一个小的知识点:
class Program
{
static void Main(string[] args)
{
Enemy enemy = new Boss();//父类声明的对象,可以让子类去构造,但反过来不行。
Boss boss = (Boss)enemy;//enemy虽然是父类去声明,但构造还是子类,所以本质上还是子类类型的,这里进行强制转换,转换成子类类型的
boss.Attack();
}
}
返回结果和上面一样。
解释:一个对象是什么类型,看它是通过什么构造的,通过子类构造,那它就有子类里的函数和字段。
4.继承的“衍生物”
a.虚方法
在认识虚方法之前,先来了解多态,多态是面向对象编程的基本特征之一,它使得派生类的实例可以直接赋予基类的对象,然后直接就可以通过这个对象调用派生类的方法。在C#中,类的多态性是通过在派生类中重写基类的虚方法来实现的。
首先,我们在父类Enemy里写一个虚方法
class Enemy
{
public virtual void Move()
{
Console.WriteLine("是Enemy的公有的Move方法");
}
}
接着在子类Boss里重写这个虚方法:
class Boss:Enemy
{
public void Attack()//子类里自己新增的方法
{
Move();//调用的是子类重写的Move方法
Console.WriteLine("Boss正在进行攻击");
}
public override void Move()
{
Console.WriteLine("是boss的移动方法");
}
}
最后在项目里调用
class Program
{
static void Main(string[] args)
{
Boss boss = new Boss();
boss.Attack();//继承:父类里所有的函数成员和数据成员都会被继承到子类里
}
}
返回结果
是boss的移动方法
Boss正在进行攻击
解释:我们在子类里重写了虚方法,之后不管在哪调用,都是调用了重写之后的方法。
b.隐藏方法
如果签名相同的方法在基类和派生类中都进行了声明,但该方法没有分别用virtual和override关键字,那么派生类方法会隐藏基类方法。
码上代码
class Enemy
{
public void Move()
{
Console.WriteLine("是Enemy的公有的Move方法");
}
}
class Boss:Enemy
{
public new void Move()//隐藏:当子类里有一个和签名和父类相同的方法时,就会把父类中的那个方法隐藏。
{
Console.WriteLine("是boss的移动方法");
}
}
class Program
{
static void Main(string[] args)
{
Boss boss = new Boss();
boss.Move();
}
}
返回结果:
是boss的移动方法
请按任意键继续.
但是在项目里用父类来声明对象,那调用的是谁的方法呢?接着码上
class Program
{
static void Main(string[] args)
{
Enemy boss = new Boss();
boss.Move();
}
}
返回结果:
是Enemy的公有的Move方法
请按任意键继续.
说明:如果是使用子类声明的对象,调用隐藏方法会调用子类的;如果是父类声明的,那么会调用父类的。
c.抽象类
如果一个类不与具体的事物相联系,而只是表达一种抽象的概念或行为,仅仅是作为其派生类的一个基类,这样的类就可以声明为抽象类。在抽象类中声明方法时,如果加上abstract关键字,则为抽象方法。类中只要有一个方法声明为抽象方法,这个类也必须声明为抽象类。
语法格式:
访问修饰符 abstract class 类名:基类或接口
{
//类成员
}
新添加一个Bird类,写一个抽象方法,让它的子类去实现这个抽象方法,码上代码
abstract class Bird //一个抽象类就是一个不完整的模板,不能实例化对象
{
public float speed;
public abstract void Fly();
}
再添加一个Crow类,继承于它
class Crow:Bird//继承一个抽象类,就必须去实现它里面所有的抽象方法,如果没有实现完所有的抽象方法,就必须定义为抽象类
{
public override void Fly()
{
Console.WriteLine("乌鸦在飞行");
}
}
在项目里声明对象去调用方法
class Program
{
static void Main(string[] args)
{
//Crow crow = new Crow();
//crow.Fly();
Bird bird = new Crow();//可以用抽象类去声明,但不可用它去构造,因为抽象类不完整
bird.Fly();
}
两种不同类型去声明对象都返回相同结果:
乌鸦在飞行
请按任意键继续.
总结:
1.一个类有抽象方法,则为抽象类,若一个类为抽象类,不一定有抽象方法;
2.若一个类继承于一个抽象类,那它要重写抽象类里所有抽象方法,否则就要被定义成抽象类。
3.可以用抽象类去声明对象,但不可用它去构造,因为抽象类不完整。
d.密封类和密封方法
C#里允许把类和方法声明为sealed。对于类,表示不能继承该类;对于方法,表示不能被重写。可以理解成一个类继承关系里的最后一层。
欢迎指正!