继承概述
继承是面向对象编程最重要的特性之一,它表示可以从一个类中派生出新的类,而且新类能继承基类的成员。在软件开发中,类的继承性使所建立的软件具有开放性、可扩充性等,并且增强了代码的可重用性。
在面向对象编程中,被继承的类称为父类或基类,继承的类称为子类或派生类。C#中提供了类的继承机制,但只支持单继承,而不支持多重继承,即在C#中一次只允许继承一个类,不能同时继承多个类,但是可以继承多个接口。
继承一个类时,类成员的可访问性是一个重要的问题。子类(派生类)不能访问基类的私有成员,但是可以访问其公共成员,这就是说,只要使用public声明类成员,就可以让一个类成员被基类和子类(派生类)同时访问,同时也可以被外部的代码访问。
为了解决基类成员访问问题,C#还提供了另外一种可访问性:protected,只有子类(派生类)才能访问protected成员,外部代码不能访问protected成员。
除了成员的保护级别外,还可以为成员定义其继承行为。基类的成员可以是虚拟的,成员可以由继承它的类重写。子类(派生类)可以提供成员的其他执行代码,这种执行代码不会删除原来的代码,仍可以在类中访问原来的代码,但外部代码不能访问他们。如果没有提供其他执行方式,外部代码就直接访问基类中成员的执行代码。
另外,基类还可以定义为抽象类。抽象类不能直接实例化,要使用抽象类就必须继承这个类,然后再实例化。
继承的基石——接口
接口是面向对象中一个非常重要的概念,而且,面向对象中的继承性和多态性主要都是通过接口来体现的。
1.接口概述
接口是一种用来定义程序的协议,它描述可属于任何类或结构的一组相关行为,可以把它看成是实现一组类的模板。接口可由方法、属性、事件和索引器或这4种成员类型的任何组合构成,但不能包含字段。
类和结构可以像类继承基类一样从接口继承,但是可以继承多个接口。当类或结构继承接口时,它继承成员定义但不继承实现。若要实现接口成员,类或结构中的对应成员必须是公共的、非静态的,并且与接口成员具有相同的名称和签名。类或结构的属性和索引器可以为接口中定义的属性或索引器定义额外的访问器。例如,接口可以声明一个带有get访问器的属性,而实现该接口的类可以声明同时带有get和set访问器的同一属性。但是,如果属性或索引器使用显式实现,则访问器必须匹配。
另外,接口也可以继承其他接口,类可以通过其继承的基类或接口多次继承某个接口,在这种情况下,如果将该接口声明为新类的一部分,则类只能实现该接口一次。如果没有将继承的接口声明为新类的一部分,其实现将由声明它的基类提供。基类可以使用虚拟成员实现接口成员;在这种情况下,继承接口的类可通过重写虚拟成员来更改接口行为。
综上所述,接口具有以下特征:
q 接口类似于抽象基类:继承接口的任何非抽象类型都必须实现接口的所有成员;
q 不能直接实例化接口;
q 接口可以包含事件、索引器、方法和属性;
q 接口不包含方法的实现;
q 类和结构可从多个接口继承;
q 接口自身可从多个接口继承。
说明:
接口使得服务的协议与实现相分离,它是组件编程的基础,在组件编程中,接口是组件向外公布其功能的唯一方法。
2.声明接口
C#中使用interface关键字声明接口,其语法格式如下:
修饰符 interface 接口名称 :继承的接口列表
{
接口内容;
}
说明:
(1)声明接口时,通常以大写字母“I”开头;
(2)声明接口时,除interface关键字和接口名称外,其它的都是可选项;
(3)可以使用new 、public、protected、internal和private等修饰符声明接口,但接口成员必须是公共的。
例 声明一个接口,该接口中包含语言和版本两个属性,还包含一个自定义方法ShowInfo,该方法用来显示定义的语言和版本。代码如下:
interface IprogramDic //自定义接口
{
/// <summary>
/// 语言(可读可写)
/// </summary>
string Language
{
get;
set;
}
/// <summary>
/// 版本(可读可写)
/// </summary>
string Version
{
get;
set;
}
/// <summary>
/// 显示定义的语言和版本
/// </summary>
void ShowInfo();
}
3.接口的实现
接口的实现通过类继承来实现,一个类虽然只能继承一个基类,但可以继承任意多个接口。声明实现接口的类时,需要在基类列表中包含类所实现的接口的名称。
C#中实现继承的语法格式如下:
class DerivedClass: BaseClass { }
说明:
继承类时,必须在子类和基类之间用冒号(:),另外,如果继承多个接口,那么在继承的每个接口之间用逗号分割(,)。
例 创建一个控制台应用程序,该程序在上例的基础上实现,Program类继承自接口IprogramDic,并实现了该接口中的所有属性和方法,然后在Main方法中实例化Program类的一个对象,并使用该对象实例化IprogramDic接口,最后通过实例化的接口对象访问派生类中的属性和方法。代码如下:
class Program : IprogramDic //继承自接口
{
string language = "";
string version = "";
/// <summary>
/// 语言
/// </summary>
public string Language
{
get
{
return language;
}
set
{
language = value;
}
}
/// <summary>
/// 版本
/// </summary>
public string Version
{
get
{
return version;
}
set
{
version = value;
}
}
/// <summary>
/// 显示定义的语言和版本
/// </summary>
public void ShowInfo()
{
Console.WriteLine("语言/t 版本");
Console.WriteLine(Language + "/t" + Version);
}
static void Main(string[] args)
{
Program program = new Program(); //实例化Program类对象
IprogramDic iprogramdic = program; //使用派生类对象实例化接口ImyInterface
iprogramdic.Language = "C#编程词典"; //为派生类中的ID属性赋值
iprogramdic.Version = " 珍藏版"; //为派生类中的Name属性赋值
iprogramdic.ShowInfo(); //调用派生类中方法显示定义的属性值
Console.ReadLine();
}
}