简单继承
最简单的三个类
public class Animal { public Animal() { Debug.Log("Construct Animal!"); } }
public class Mammal : Animal { public Mammal() { Debug.Log("Construct Mamal!"); } }
public class Sheep : Mammal { public Sheep() { Debug.Log("Construct Sheep!"); } }
在main里面
Sheep sheep = new Sheep();
子类的构造函数会依次运行基类的构造函数,没有异议。
须要注意的是,没有特别声明,子类都会自己主动去找父类中没有參数的构造函数,假设基类中没有,则须要在子类的构造函数中调用。比方:
public class Animal{ int age; public Animal(int _age) { age = _age; Debug.Log("Construct Animal!"); } }
则子类的构造函数就要这样写
public Mammal():base(0) { Debug.Log("Construct Mamal!"); }
在基类Animal中加入函数
public void Eat() { Debug.Log("Animal Eat!"); }
以下谈一下方法的覆盖
在子类Sheep中覆盖定义Eat方法
public new void Eat() { Debug.Log("Sheep Eat!"); }
这里的newkeyword表示隐藏基类中的方法。官方解释例如以下:
new keyword能够显式隐藏从基类继承的成员。
隐藏继承的成员时。该成员的派生版本号将替换基类版本号。
尽管能够不使用 new 修饰符来隐藏成员,但将收到编译器警告。假设使用 new 来显式隐藏成员,将禁止此警告。
測试代码:
Sheep sheep = new Sheep(); Animal animal = new Sheep(); sheep.Eat(); animal.Eat();
结果是这种
没有发生多态行为,声明的基类对象。运行的就是基类方法,声明的子类对象,运行的就是子类方法。
在子类的函数中,都有一个base变量。能够觉得是一个对基类的引用,通过base就能够调用基类的方法。
多态
多态就是多态就是父类引用指向子类对象,调用方法时会调用子类的实现。而不是父类的实现,这叫多态。
基类Animal中定义函数
public virtual void Birth() { Debug.Log("Animal Birth!"); }
Sheep中overrride一下
public override void Birth() { Debug.Log("Sheep Birth!"); }
測试代码
Sheep sheep = new Sheep(); Animal animal = new Sheep(); animal.Birth();
运行结果
有以下两个须要注意的点
1.子类调用父类的方法
当然是直接用base了。
2.继承链中的虚方法
不管在虚拟成员和最初声明虚拟成员的类之间已声明了多少个类。虚拟成员永远都是虚拟的。假设类 A 声明了一个虚拟成员。类 B 从 A 派生,类 C 从类 B 派生,则类 C 继承该虚拟成员,而且能够选择重写它。而不管类 B 是否为该成员声明了重写。
Sealedkeyword的使用方法
Sealedkeyword用来阻止派生类重写虚拟成员。还是举例说明。
基类Animal中定义方法
public virtual void Move() { Debug.Log("Animal Move!"); }
Mammal中sealed override这个函数
public sealed override void Move() { Debug.Log("Mammal Move!"); }
这时候在Sheep中已经无法overide这个函数了,由于在Sheep看来,基类的Move是被当作一个普通函数来处理的,假设要定义自己的Move函数,就要加new,像这样
public new void Move() { Debug.Log("Sheep Move!"); }
写点代码来測试多态性
Animal animal = new Animal(1); Animal animal1 = new Mammal(1); Animal animal2 = new Sheep(); Sheep sheep = new Sheep(); animal.Move(); animal1.Move(); animal2.Move(); sheep.Move();
运行结果
第一个无话可说。直接运行了Animal的move函数
第二个,正常的多态
第三个有点意思。多态到Mammal就打住了
第四个就是普通的运行Sheep类的成员函数。
abstractkeyword的使用
官方解释:abstract 修饰符指示所修饰的内容缺少实现或未全然实现。
abstract 修饰符可用于类、方法、属性、索引器和事件。
在类声明中使用 abstract 修饰符以指示某个类仅仅能是其它类的基类。标记为抽象或包括在抽象类中的成员必须通过从抽象类派生的类来实现。
接地气的解释:abstract类用于搭建子类的框架。子类必须实现当中的abstract方法。使用的也是overridekeyword。
abstract方法和vitual方法的差别
abstract方法没有函数体,子类一定要有相应方法的实现。
vitual方法子类能够选择实现也能够选择不实现。
两个都能够用于实现多态。
抽象类不能实例化。
抽象类的用途是提供一个可供多个派生类共享的通用基类定义。比如,类库能够定义一个抽象类。将其用作多个类库函数的參数。并要求使用该库的程序猿通过创建派生类来提供自己的类实现。
接口
接口包括类或结构能够实现的一组相关功能的定义。
比如,使用接口能够在类中包括来自多个源的行为。
由于C#语言不支持多重继承,所以该功能非常重要。
此外,假设要模拟结构的继承,也必须使用接口。由于它们无法实际从还有一个结构或类继承。
定义一个简单的接口,仅仅有接口函数的定义,没有实现。
public interface ISay { void SayHello(); void SayFuck(); }
public class Sheep : Mammal, ISay
则Sheep类中必须要有ISay中定义的接口的定义
public void SayHello() { Debug.Log("ISay Hello"); } public void SayFuck() { Debug.Log("ISay SayFuck"); }
測试代码
Sheep sheep = new Sheep(); sheep.SayHello(); sheep.SayFuck();
运行结果
接口有以下几个属性
接口相似于抽象基类。实现接口的不论什么类或结构都必须实现其全部成员。
接口无法直接进行实例化。其成员由实现接口的不论什么类或结构来实现。
接口能够包括事件、索引器、方法和属性。
接口不包括方法的实现。
一个类或结构能够实现多个接口。一个类能够继承一个基类,还可实现一个或多个接口。
參考
MSDN