在面向对象编程中,有两种截然不同的继承类型,实现继承和接口继承;C#中不支持多重继承,C#类可以派生自另一个类和任意多的接口
/// <summary> /// 基类 /// </summary> class Person { /// <summary> /// 使用virtual关键字定义的方法允许在派生类中使用override重写 /// </summary> public virtual void SayHello() { Console.WriteLine("基类的SayHello"); } } /// <summary> /// 派生自Person /// </summary> class ChinaPerson : Person { /// <summary> /// 使用override关键字重写基类的SayHello方法 /// </summary> public override void SayHello() { Console.WriteLine("你好"); } } /// <summary> /// 派生自Person /// </summary> class ThailandPerson : Person { public override void SayHello() { Console.WriteLine("萨瓦迪卡"); } }
把一个基类函数声明为virtual,就可以在任何派生类中重写该函数,virtual也适用于属性;需要注意:成员字段和静态函数都不能声明为virtual,因为这个概念只对类中的实例成员有意义
如果签名相同的方法在基类和派生类中都进行了声明,但该方法没有声明为virtual和override,派生类会隐藏基类方法
class Person { public void SayHello() { Console.WriteLine("基类的SayHello"); } } class ChinaPerson : Person {
//提示:隐藏继承的成员Person.SayHello,如果有意的,请使用关键字new public void SayHello() { Console.WriteLine("你好"); } }
修改后
class Person { public void SayHello() { Console.WriteLine("基类的SayHello"); } } class ChinaPerson : Person { public new void SayHello() { Console.WriteLine("你好"); } }
C#中可以使用base.<MethodName>()这种语法来调用方法的基类版本
class Person { public virtual void SayHello() { Console.WriteLine("基类的SayHello"); } } class ChinaPerson : Person { public override void SayHello() { base.SayHello(); Console.WriteLine("你好"); } }
C#中允许把类或函数声明为abstract,抽象类不能被实例化.抽象函数也不能直接实现,必须在非抽象的派生类中重写
C#允许把类或方法声明为sealed,对于类而言,这表示不能继承该类,对于方法而言,这表示不能重写该方法
class Program { static void Main(string[] args) { ChinaPerson chinaPerson = new ChinaPerson(); Console.ReadKey(); } } class Person { static Person() { Console.WriteLine("Person静态构造函数"); } public Person() { Console.WriteLine("Person实例构造函数"); } } class ChinaPerson : Person { static ChinaPerson() { Console.WriteLine("ChinaPerson静态构造函数"); } public ChinaPerson() { Console.WriteLine("ChinaPerson实例构造函数"); } }
输出
ChinaPerson静态构造函数
Person静态构造函数
Person实例构造函数
ChinaPerson实例构造函数
构造函数执行顺序为:调用System.Object.Object()->ChinaPerson被实例化所以调用自身的静态构造函数->跳到ChinaPerson的实例构造函数发现基类Person->Person类被调用,所以调用自身的Person静态构造函数->Person实例无参构造函数->:ChinaPerson实例无参构造函数(先调用System.Object的构造函数,再按照继承的层次结构从上往下进行,直到最终要实例化的类为止)
可以使用base关键字来实现不同构造函数的调用
指定一组函数成员而不实现成员的引用类型,其它类型和接口可以继承接口
接口继承中又分为隐式实现和显式实现
interface IPerson { void SayHello(); } /// <summary> /// 隐式实现接口 /// </summary> class ChinaPerson : IPerson { public void SayHello() { Console.WriteLine("你好"); } } /// <summary> /// 显式实现接口 /// </summary> class ThailandPerson : IPerson { void IPerson.SayHello() { Console.WriteLine("莎娃迪卡"); } }
对于隐式实现的接口调用这两种方式都可以
ChinaPerson chinaPerson = new ChinaPerson(); IPerson person = new ChinaPerson(); person.SayHello(); chinaPerson.SayHello();
对于显式实现的接口调用:只能使用接口调用
IPerson thailandPerson = new ThailandPerson(); thailandPerson.SayHello();
相同点:
区别:
抽象基类可以定义字段/属性/方法实现.接口只能定义属性/索引器/事件/方法声明
抽象类是一个不完整的类,需要通过集成进一步细化.而接口更像是一个行为规范,表名我能做什么
接口是可以被多重实现的,可以有多个类实现接口,因为类的单一继承性,抽象类只能被单一继承
抽象类实现继承需要使用override关键字,接口则不用
如果抽象类实现接口,可以把接口方法映射到抽象类中作为抽象方法不必实现,而在抽象类的子类中实现接口方法
抽象类表示的是,这个对象时什么;接口表示都是,这个对象能做什么;使用抽象类是为了代码的复用,使用接口是为了实现多态性
相同点:
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。