抽象类与接口
1.抽象类
举个例子:去书店买书。这句话描述的就是一个抽象行为,但底是去哪家书店,买什么数。“去书店买书”这句话中,并没有买书行为必须包含的确定信息,如果将去书店买书这个动作封装为一个行为类,那么这个类就应该是一个抽象类。
注:1.C#中规定,类中只要有一个方法声明为抽象方法,这个类也必须声明为抽象类。
2.抽象类中不一定所有方法都是抽象方法或抽象属性。
抽象类具有以下特性:
l 抽象类不能被实例化。
l 抽象类可以包含抽象方法和抽象的访问器。
l 不能用sealed修饰符修饰该抽象类,这意味着抽象类不能被继承。
l 从抽象类派生的非抽象类,必须包括继承的所有抽象方法和抽象访问器的实现。
l 在方法或属性声明中用abstract修饰符,以指示方法或属性为抽象方法或抽象属性。
抽象方法具有下列特性:
l 抽象方法是隐式的虚方法(virtual),所以在实现抽象方法或抽象属性时需要用override来修饰实现方法或实现属性。
l 只允许在抽象类中使用抽象方法声明。
l 因为抽象方法声明不提供实际的实现,所以没有方法体。方法声明是以一个分号结束,并且在签名后没有大括号{}。
l 实现由一个重载方法提供,此重载方法是非抽象类的成员。
l 在抽象方法声明中使用static或virtual修饰符是错误的。
l 抽象属性必须写访问器。
l 如果继承了某个抽象类,那么就要实现抽象类里面所有的抽象方法和属性(除非继承类也是抽象类)。
注:如果一个没有用Abstract修饰的类继承了一个抽象类,但是并没有全部实现抽象类里面所有的抽象方法和属性,那么这个类就会被默认为抽象类(尽管没有用Abstract修饰)。
在设计和声明一个抽象类时,注意:不要在抽象类中定义公共或内部受保护的构造函数。如果需要构造函数,应该在抽象类中声明为受保护的或内部构造函数。应该至少提供一个该抽象类的具体实现。
定义了抽象方法或抽象属性,那么在继承类中就必须为抽象类
//定义一个抽象类
public abstract class Shape
{
public abstract float area();
public abstract string Why//抽象属性必须写访问器,不然会报错,不能实现抽象属性。
{
get;
set;
}
public void pring()
{
Console.WriteLine(Why);
}
}
//继承抽象类,并实现抽象里面所有的抽象方法和属性。
public class Rectangle : Shape
{
private int length;
private int width;
private string why;
public override string Why
{
get
{
return why;
}
set
{
why = value;
}
}
public Rectangle(int length, int width) //构造器
{
this.length = length;
this.width = width;
}
public override float area() //计算面积
{
return (float)(length * width);
}
public void showArea()
{
Console.WriteLine(Why);
Console.WriteLine("正方形面积为:" + area() + "\n");
}
}
//主类
class Program
{
static void
{
Rectangle rectangle = new Rectangle(1, 2);
rectangle.Why = "这是什么啊?";
rectangle.showArea();
Console.Read();
}
}
2.接口
接口提供了一种契约,让使用接口的用户必须严格遵守接口提供的约定。
接口具有下列属性:
l 接口类类似于抽象类,继承接口的然后非抽象类型都必须实现接口的所有成员。
l 不能直接实例化接口。
l 接口可以包含事件、索引器、方法和属性。
l 接口不包含方法的实现,而抽象类可以包含方法的实现。
l 类和结构可以多个接口继承。
l 接口自身也可以从多个接口继承。
l 接口的成员必须是方法、属性、事件或索引器。
l 接口不能包含常量、字段、运算符、实例构造函数、析构函数或类型,也不能包含任何种类的静态成员。
l 接口成员声明包含任何修饰符都十余编译时错误。集体来说就是不能用任何修饰符来修饰接口中的成员。
l 所有接口成员都隐式地具有public访问属性。
l 关键字Abstract和sealed,virtual,static不能在接口中使用,因为这两个修饰符在接口定义中是没有意义的(它们不包含执行代码,所以不能直接实例化,且必须是可以继承的)
注:在定义接口中不能用virtual ,Abstract,sealed关键字来修饰接口中的属性或方法,但是可以在实现接口的类中使用。在实现接口的类中使用virtual的作用就在于将该类为基类时,子类对实现重写(父类实现了接口,子类自然拥有接口中的方法,而通过重载父类中的方法来表现自己的方法)
接口不能单独存在,不能像实例化一个类那样实例化接口。
如:
public interface Shap
{
float area(); 接口中不能用关键字virtual来修饰。
}
public class Rectangle:Shap //继承接口
{
public virtual float area() //实现接口可以用virtual关键字来修饰,
{
return (float)(2 * 3);
}
}
//一个接口
public interface Shap
{
float area();
}
public class Rectangle:Shap //继承接口
{
public int length;
public int width;
public Rectangle(int length, int width) //构造器
{
this.length = length;
this.width = width;
}
public float area() //实现接口
{
return (float)(length * width);
}
public void showArea()
{
Console.WriteLine("面积为:" + area() + "\n");
}
}
//主类
class Program
{
static void
{
Rectangle rectangle = new Rectangle(1, 2);
rectangle.showArea();
Console.Read();
}
}
3.接口于抽象类
抽象类可以拥有抽象成员(没有代码体)和非抽象成员(它们拥有代码体,也可以是虚拟的,这样就就可以在派生类里面重写)。接口成员必须都在使用接口的类上实现——它们没有代码体。
接口成员是公共的(因为它们倾向于外部使用),但抽象类的成员可以是私有的(只要它们不是抽象的)、受保护的、内部的或受保护的内部成员(其中受保护的内部成员只能在应用程序的代码或派生类中访问)。此外,接口不能包含字段、构造函数、析构函数、静态成员或常量。
抽象类用于部分实现一个类,再由用户按需求对其进行不同的扩展和完善;接口是定义一个行为的规范或规定。
抽象类在组建的所有实现间提供通用的已实现功能;接口创建在大范围全异对象间使用的功能。
抽象类主要用于关系密切的对象;而接口适合为不相关的类提供通用功能。
抽象类主要用于设计大的功能单元;而接口用于设计小而简练的功能块。
说明:抽象类主要用作对象系列的基类,共享某些主要特性,例如共同的目的或结构,接口则主要用于类,这些类的基础水平上有所不同,但仍可以完成某些相同的任务。