接口这个概念一点都不新鲜,接触了C++,C#,Java等主流语言都包含了接口这个让人爱让人很的小东东。
让人爱是它能帮助我们完成一些相对复杂的操作和逻辑关系的保持,尤其是在包含很多复杂类型和继承关系的情况下。让人恨是因为它看起来并不像表面那样简单易用,其中涉及到了诸多的访问控制,再加上接口间的继承和派生。所以简单写一个接口总结,权当读书笔记,好记性不如烂笔头。
先来做点知识储备的功课。
子类和基类以及他们的继承关系。废话少说 上代码
- public class Animal
- {
- public int NumberOfLegs;
- public void Eat()
- {
- //code to make the animal eat
- }
- }
- public class Bird : Animal
- {
- public double Wingspan;
- public void Fly()
- {
- // code to make the bird fly
- }
- }
- public button1_Click(Object sender, EventArgs e)
- {
- Bird tweety = new Bird();
- tweety.Wingspan = 7.5;
- tweety.Fly();
- tweety.NumberOfLegs = 2;
- tweety.Eat();
- }
类的继承用冒号来实现,跟在冒号后面的是基类名。注意一点,C#当中不允许多继承也就是说一个子类只能从继承自一个父类。这也好理解,就好比你只能有一个亲生老爹一样。子类继承了父类就自动获得了父类中所有的public和protect方法和字段。父类中private修饰的方法和字段对子类来说是不可见的。父类中protect对于子类是可见的,对于其他类是不可见的。当一个类被sealed修饰时(),说明他是不可被其他类所继承的,用太监来形容它我感觉是很贴切的。
子类对于父类的继承不仅仅是方法和字段的获取,最重要的是保证一个逻辑关系的向下延伸,多个子类拥有一个父类,他们都自动的继承了父类的一些属性。同时他们之间也有不同,就像兄弟几个只是长得像,但是肯定还是各自有各自的特点的(当然了 我们不排除双胞胎的特殊情况,不过在程序设计当中这么做似乎没有任何意义)。好了,那么如何能保证兄弟之间的差异呢?这就仰仗于子类覆盖或替换父类的方法。
父类中被virtual关键字修饰的方法在子类中都可以被重写,虽然方法名是一样的,但是各个子类都有着不同的功能。子类中必须用override来修饰准备替换的方法。
- public class Bird
- {
- public virtual void Fly()
- {
- // code to make the bird fly
- }
- }
- public class Penguin : Bird
- {
- public override void Fly()
- {
- MessageBox.Show("Penguins can't fly!");
- }
- }
鸟类都有一个共同的方法Fly(),但并不是所有的鸟都能飞,比如企鹅,鸵鸟。重写就很好的解决了这一问题,既保证了鸟类和企鹅之间的类继承关系,同时也解决了不同鸟之间的差异问题。
下面介绍一下基类对于子类的访问。在程序设计时我们可以用父类的引用来指向子类的实例。当然这么做会有一定的缺点,子类对于父类是透明的。父类并不知道谁继承了他,更不知道子类当中又新增了什么字段和方法。所以父类的引用只能访问那些在父类当中已经存在的字段和方法。乍看起来有了这样的限制,父类引用指向子类实例好像就没什么实际意义了。但是我们在实际应用中确实时常用到这个小技巧的。
我们可以用一个基类引用的数组来保存子类的实例,来访问他们父类中共同的方法和字段。同样的方法也适用于接口,我们下面会说到。
写子类时要注意一点,父类如果有自己定义的构造函数,那子类也必须有构造函数。如果父类有多个构造函数那么子类至少有一个。父类的构造函数在子类构造之前执行。这个很好理解。
下面开始介绍接口。
首先要说明的就是接口也是一个类,只不过他比平时我们用到的类特别一些。原因主要有以下几点:
- 接口中只有函数的定义,没有实现。
- 接口中没有变量的定义,但是可以定义属性。
- 接口没有构造函数,而且接口中的函数不需要访问修饰关键字修饰。都是public的。
- 由于接口没有构造函数,而且编译器也不自动生成默认的构造函数,所以接口不能被实例化,但是可以被继承。
接口只能被类所实现,而且实现这个接口的类必须实现接口中所有的方法。接口就像一个契约一样,保证该类具有接口中描述的特性。
接口更像是对一个类功能的补充。每当一个类实现了这个接口,那么就可以用这个接口的引用来指向那个类的实例。当然了,通类的继承一样,接口引用只能访问接口中含有的方法和属性。同时一个类可以实现多个接口,当然责任是必须实现所有接口当中的方法。就像一个人可以有很多个干爹一样。
简单说一下接口的继承,和类的继承没有太大差别。基接口的引用可以指向实现了子接口的类的实例。想一想这样做的实际意义。可以把接口看做是一个附加的功能。很多不同的类都可以拥有这个功能,各个类之间不一定都有继承关系。但是他们都可以用一个接口引用的数组来访问(仅仅能访问接口中的方法和属性)。
之前介绍的父子关系,包括类和接口,都是由下向上的转换。下面介绍一种特殊的方法,可以让这种关系倒置。父一样可以操作子中的方法。
实现这一功能需要用到的是is和as关键字。
- public interface Isendmail
- {
- //一个接口,附加了送信的功能
- void sendmail();
- }
- public class Pigeon : Bird, Isendmail
- {
- // ......
- void sendmail()
- {
- // send mail...
- }
- }
- Bird[] bir = new Bird[2];
- bir[0] = new Penguin();
- bir[1] = new pigeon();
- for( int i =0; i<bir.Length; i++)
- {
- if(bir[i] is Isendmail)
- {
- Isendmail mail;
- mail = bri[i] as Isendmail;
- mail.sendmail();
- }
- }
特别注意接口引用只能访问接口当中声明的方法和属性。
目前也就这么多,有机会把虚类也总结起来。
转载于:https://blog.51cto.com/xiangsen/622154