目录
——————————————————————————————————————————————————
18.11.27首次编辑
————————————————————————————————————————————————————
接口和抽象类是面向对象中最重要的两个概念,两者的作用相似,都是同一类型和规范派生类的属性和方法。
关于接口:
接口的说明
- 接口是一种程序的约定,本身并不去实现成员的方法,而是通过派生类来实现。接口可以使得程序更加清晰,更加具有条理【主要作用】。
- 实际上,接口只是一种约定,定义了该接口有哪些方法,但是并未对这些方法具体的实现。
- 接口定义了语法合同 "是什么" 部分,派生类定义了语法合同 "怎么做" 部分,接口内的方法在派生类中必须全部实现。
- 接口定义了属性、方法和事件,这些都是接口的成员。接口只包含了成员的声明。成员的定义是派生类的责任。接口提供了派生类应遵循的标准结构。
-
接口使得实现接口的类或结构在形式上保持一致。
抽象类在某种程度上与接口类似,但是,它们大多只是用在当只有少数方法由基类声明由派生类实现时。
接口的声明方法
例如:这段代码定义了接口 IMyInterface。通常接口命令以 I 字母开头,这个接口只有一个方法 MethodToImplement(),没有参数和返回值,当然我们可以按照需求设置参数和返回值。
//接口使用 interface 关键字声明,它与类的声明类似。接口声明默认是 public 的。下面是一个接口声明的实例:
interface IMyInterface
{
void MethodToImplement();
}
//接口一般定义格式如下所示。
[attributes] [modifiers] interface identifier [:base-list] {interface-body}[;]
attributes(可选): 属性,一般省略,目前没遇到实例
modifiers(可选):修饰符,即public,注意显性和隐性的区别:https://www.cnblogs.com/summer1987/p/4600100.html
identifier:接口名称。
base-list(可选):
interface-body:
接口需要注意的几点:
- 接口内的方法不能用public abstract等修饰。接口内不能有字段变量,构造函数。
- 接口内可以定义属性(有get和set的方法)。如string color { get ; set ; }这种。
- 实现接口时,必须和接口的格式一致。
- 必须实现接口的所有方法。
- 接口中只包含成员的签名,接口没有构造函数,所有不能直接使用 new 对接口进行实例化。接口中只能包含方法、属性、事件和索引的组合。接口一旦被实现,实现类必须实现接口中的所有成员,除非实现类本身是抽象类。
- C# 是单继承,接口是解决 C# 里面类可以同时继承多个基类的问题【解决多继承问题】,类不能继承两个基类。要实现多重继承的功能,就要利用类和接口之间的继承关系。类可以继承两个以上的接口,也可以在继承基类的同时,再继承另外一个接口。所以实现多重继承关系有两种方法:接口的多重继承【多个接口】和类的多重继承【单个基类+额外接口】。
接口的一个实现:
using System;
//1、接口常常以字母I开头
interface IMyInterface
{
// 接口成员,可以在其中添加参数和返回值,但不能在接口中实现方法,仅仅作为“目录”的功能
void MethodToImplement();
}
//一个类,来实现这个接口,语法上和继承很像
class A : IMyInterface
{
static void Main()
{
//2、用类A来实例化一个对象,继承接口
A iImp = new A();
iImp.MethodToImplement();
}
//3、在这里对方法进行实现,方法名必须与接口定义的方法名一致。
public void MethodToImplement()
{
//方法在这里实现
Console.WriteLine("MethodToImplement() called.");
}
}
关于实现接口的语法:很类似类的继承,通常I开头
class InterfaceImplementer : IMyInterface
接口的继承
如果是接口进行了继承(接口继承接口):
如果一个接口继承其他接口,那么实现类或结构就需要实现所有接口的成员。
例:两个接口 IMyInterface 和 IParentInterface。
using System;
//父接口
interface IParentInterface
{
void ParentInterfaceMethod();
}
//子接口,这里继承了父接口
interface IMyInterface : IParentInterface
{
void MethodToImplement();
}
//类,实现了子接口
class InterfaceImplementer : IMyInterface
{
static void Main()
{
//实例化一个类的对象,并分别调用两个接口的方法
InterfaceImplementer iImp = new InterfaceImplementer();
iImp.MethodToImplement();
iImp.ParentInterfaceMethod();
}
//对子接口方法进行实现
public void MethodToImplement()
{
Console.WriteLine("MethodToImplement() called.");
}
//对父接口方法进行实现
public void ParentInterfaceMethod()
{
Console.WriteLine("ParentInterfaceMethod() called.");
}
}
关于抽象类:
抽象类的作用和接口类似,同样也定义了一些为实现的方法。与接口不同的是,其中有一些方法已经实现了。所以,从概念上来讲,抽象类是介于接口和类之间的一种特殊的类。
抽象类的定义和特征:
-
不能初始化的类被叫做抽象类,它们只提供部分实现,但是另一个类可以继承它并且能创建它们的实例,有未被实现的方法。抽象类不可以new对象。
-
"一个包含一个或多个纯虚函数的类叫抽象类,抽象类不能被实例化,进一步一个抽象类只能通过接口和作为其它类的基类使用。
有时候,类表达的并不是一个具体的事物,而是一个比较抽象的概念。所以,C#引入了一个新的概念,那就是抽象类。 抽象类使用abstract关键字定义,此关键字是放在类class关键字的前面,表示此类属于抽象类。例如定义一个抽象类Shape,就可以定义为如下的代码
abstract class Shape
{
// 抽象类成员
}
抽象类的功能和接口类似,其中也定义了一些派生类必须要实现的方法。抽象类中的这些方法被称之为抽象方法,使用abstract关键字定义。如下面的代码就是在抽象类中定义了一个抽象方法。
abstract class Shape
{
abstract public double GetArea();
}
在继承此抽象类的派生类中,必须要实现抽象方法GetArea()。在派生类中使用override关键字重写此抽象方法来实现。
抽象类中的抽象方法是通过派生类来实现的,而抽象类又可以继承接口,这样三者之间就形成了比较复杂的继承关系。在设计代码时,灵活利用三者的继承关系,可以使得“低耦合,高内聚”的特点体现得更加明显。
使用抽象类:
要求:
创建一个抽象类Shape,然后通过其派生类Rectangle实现其抽象方法GetArea()
namespace 抽象类test
{
//抽象类,作为基类来使用
abstract class Shape
{
//注意抽象方法的定义也要加上abstract
abstract public double GetArea(double a, double b);
}
class Rectangle : Shape
{//注意这里继承了抽象类后,实现方法也要加上override的修饰词
public override double GetArea(double a,double b)
{return a * b;}
}
class Program
{
static void Main(string[] args)
{
Rectangle rectangle = new Rectangle();
Console.WriteLine("面积:"+ rectangle.GetArea(20, 20));
Console.ReadKey();
}
}
}
抽象类之间的继承关系:
不只是类可以继承抽象类,抽象类之间也可以存在继承关系。
代码改1:
要求:
在上一个练习要求下创建一个抽象类Graph,并继承了抽象类Shape,添加方法FillColor(),并在MAIN中调用
namespace 抽象类test
{
abstract class Shape
{
abstract public double GetArea(double a, double b);
}
abstract class Graph:Shape
{
abstract public String FillColor(String a);
}
class Rectangle : Graph
{
public override string FillColor(String a)
{return a;}
public override double GetArea(double a,double b)
{return a * b;}
}
class Program
{
static void Main(string[] args)
{
Rectangle rectangle = new Rectangle();
Console.WriteLine("面积:"+ rectangle.GetArea(20, 20));
Console.WriteLine("颜色为:"+rectangle.FillColor("绿色"));
Console.ReadKey();
}
}
}
抽象类、接口、类三者的继承:
不只是抽象类之间,以及和类之间有继承关系,抽象类和接口之间同样可以有继承关系。
抽象类在继承接口时,可以实现接口定义的方法,也可以把该方法定义为抽象方法,而不去实现。
实例:
namespace 抽象类test
{
//新增接口,在接口中声明方法,这里不能直接实现该方法,而要通过派生类来实现
interface IShape
{
double GetArea(double x, double y);
}
//抽象类1,继承了接口
abstract class Shape:IShape
{ //将接口中的方法抽象化,不实现
abstract public double GetArea(double a, double b);
}
//抽象类2,继承了抽象类1
abstract class Graph:Shape
{
abstract public String FillColor(String a);
}
//类1,继承了抽象类2,并在这里实现了最上边接口的方法
class Rectangle : Graph
{
public override string FillColor(String a)
{return a;}
public override double GetArea(double a,double b)
{return a * b;}
}
class Program
{
static void Main(string[] args)
{
Rectangle rectangle = new Rectangle();
Console.WriteLine("面积:"+ rectangle.GetArea(20, 20));
Console.WriteLine("颜色为:"+rectangle.FillColor("绿色"));
Console.ReadKey();
}
}
}