第八章抽象类和接口
目标
抽象类和抽象方法
- 用来列举一个类所需要的行为
- 不明确提高具体实现方法
- 必须有其子类实现它的抽象方法
- 抽象方法
·只指明方法的返回值类型、方法名称及参数,而不提供方法的实现。
抽象类语法
[访问修饰符]abstract class类名
{
代码
}
抽象类案例
abstract class People//抽象类
{
string name;
string sex;
public string Name { get => name; set => name = value; }//字段封装
public string Sex { get => sex; set => sex = value; }//字段封装
/*public virtual void Speak()
{
Console.WriteLine("大家好,我是一个人");
}*/
public abstract void Speak();//把Speak定义为抽象方法,使用关键字abstract
}
抽象类特性
- 抽象类不能实例化
- 抽象类可以包含抽象方法和抽象访问器
- 不能用sealed修饰符修改抽象类,这意味着抽象类不能被继承
- 从抽象类派生的非抽象类必须包括继承的所有抽象方法和抽象访问器的实现
- 抽象类里面只有方法的声明,没有方法的主体
- 抽象方法不能是静态的,不能用static
- 抽象方法不能标记为virtual
抽象类注意事项
注意:
(1)抽象方法只能在派生类中才能真正实现
(2)一个类中只要有一个抽象方法,该类必须定义为抽象类
(3)抽象方法只指明返回值类型、方法名称及参数
(4)定义成抽象方法的目的在于指定派生类必须实现这一方法的功能
(5)抽象类可以有构造方法,但是构造方法不能直接被调用而只能由派生类的构造方法调用
虚方法和抽象方法
虚方法 | 抽象方法 |
---|---|
用virtual修饰 | 用abstract修饰 |
要有方法体,哪怕是一个分号 | 不允许有方法体 |
可以被子类override | 必须被子类override |
除了密封类都可以写 | 只能在抽象类中 |
接口
全部是为实现的方法
语法
[属性][修饰符]interface 接口名
{
//接口主体
}
- 接口中只能声明方法、属性、索引器和事件
- 接口不能声明字段、构造方法、常量和委托
- 接口的成员默认是public的,如果明确指定成员的访问级别会报编译错误
- 接口中所有的方法、属性和索引器都必须没有实现
- C#中的接口以大写字母“I”开头
接口定义内容
//定义接口,定义后不需要改变,需要不同功能,继承时扩展即可
interface IPrint
{
void Print(); //只定义,不实现
//IPerson(); //错误,未写返回值
//string name; //错误,定义字段
//public void GetlDcard(); //错误,指定访问级别
//void GetName(); //正确
//void GetAge(string s); //正确
//int GetHeight(); //正确
}
使用接口
- 类实现接口与继承一样,需要使用冒号运算符
- 与抽象类不同的是,类是实现了接口中的方法而不是重写,所以实现接口的方法时不需要override关
键字。
//A继承接口
class A IPrint
{
//实现接口方法,必须有,//当然还可以再添加其它的字段、属性、方法
public void Print()
{
System.Console.WriteLine("A");
}
}
//B继承接口
class B:IPrint
{
public void Print()
{
System.Console.WriteLine("B");
}
}
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace AppTest
{
class Demo interface
{
static void Main(string[]args)
{
//使用(注意,这里是使用接口IPirnt,下面是不同的实例,获得不同功能)
IPrint I;
I=new A();//实例化A,将打印出A
I.Print();
I=new B();//实例化B,将打印出B
I.Print();
Thread.Sleep(3*1000);//暂停3秒,看打印结果
}
}
}
思考
- 写的不错,不过这个例子还缺少一部分,人家可以说我可以在基类上定义Print(),PrintPreview()2个虚函数,让后续不同打机的类继承这个基类,override虚函数,然后通过基类指针一样可以实现这个功能。
- 如果你这么说,如果要给HP打印机和IBM打印机增加一个新功能如Scan(),如果用基类虚函数就得重新修改基类,基类修改会影响到所有继承他的类,系统成型后修改基类是非常危险的,而用接口只需让HP的,IBM的打印类再继承一个Scan接口就行了,不会影响到其他类,这就是接口优越于虚函数的地方。
接口作为方法的参数
继承基类并实现接口
- 一个类既可以派生自另一个类还可以同时实现某个接口
- 一个类继承基类同时又实现接口时基类名要写在接口名的前面
多重接口实现
- 一个类可以同时实现多个接口
- 实现多个接口只需要在定义类时在后面添加一个逗号和接口名
- 类的代码中实现新接口的所有方法
语法
static void Main(string[] args)
{
IPrint iHp = new PrintHP();
IPrint iIBM = new PrintIBM();
PrintPhoto(iHp);
PrintPhoto(iIBM);
}
//打印照片的方法
public static void PrintPhoto(IPrint i)//接口作为参数
{
i.Print();
}
接口作为参数的意义
- 实际上要接收的是一个实现这个接口的对象每个实现该接口的对象代码不一样,那么传递给方法执行时的结果也就不一样。
- 通过接口也就实现了多态
接口的绑定
- 接口绑定就是把不同的接口合在一起
- 一个新的接口
//用接口继承接口,就是接口的绑定
interface ISumSports:ISports,ILaLaDui
{
void KaiMuShi();
}
is和as关键字
is
- 测试一个实例是不是另一个类型
as
- 同is
- 同时把实例转换为另一种类型,如果转换不成功则返回null
static void Main(string[] args)
{
//is关键字:判断一个实例是不是另一种数据类型,返回值为true或者false
Sports s1 = new Sports();
if (s1 is ISports)
{
s1.KaiMuShi();
}
else
{
s1.Sing();
}
//as关键字,同is,把一种类型作为另一种类型使用,如果转换成功,返回目标数据类型,转换不成功,返回null;
ISumSports isum = s1 as ISumSports;
if (isum !=null)
{
isum.Dance();
}
else
{
isum.QianQiu();
}
抽象类与接口比较
总结
抽象方法
- 没有代码实现的方法,使用abstract关键字修饰
抽象类
- 使用abstract关键字修饰
- 是指包含0到多个抽象方法的类
- 抽象类不能实例化
- 含有抽象方法的类必须是抽象类
- 重写抽象类的方法也用override关键字
接口
- 使用interface关键字修饰
- 接口中只定义方法的原型,接口中不能有字段和常量
- 继承接口的类必须实现接口中所有的方法才能实例化
is和as关键字
- 测试一个实例是不是另一个类型
- as同时把实例转换为另一种类型,如果转换不成功则返回null
评论 (0)