interface IListBox: IControl
{
void SetItems(string[] items);
}
class ComboBox: IControl, ITextBox, IListBox
{
void IControl.Paint() {...}
void ITextBox.SetText(string text) {...}
void IListBox.SetItems(string[] items) {...}
}
在基类列表中命名的 IControl、由 ITextBox 继承的 IControl 和由 IListBox 继承的 IControl 不可能有各自不同的实现。事实上,没有为这些接口提供单独实现的打算。相反,ITextBox 和 IListBox 的实现共享相同的 IControl 的实现,因而可以简单地认为 ComboBox 实现了三个接口:IControl、ITextBox 和 IListBox。
基类的成员参与接口映射。在下面的示例中
interface Interface1
{
void F();
}
class Class1
{
public void F() {}
public void G() {}
}
class Class2: Class1, Interface1
{
new public void G() {}
}
Class1 中的方法 F 用于 Class2 的 Interface1 的实现中。
1.1.1 接口实现继承
类继承由其基类提供的所有接口实现。
如果不显式地重新实现 (re-implementing) 接口,派生类就无法以任何方式更改它从其基类继承的接口映射。例如,在下面的声明中
interface IControl
{
void Paint();
}
class Control: IControl
{
public void Paint() {...}
}
class TextBox: Control
{
new public void Paint() {...}
}
TextBox 中的 Paint 方法隐藏 Control 中的 Paint 方法,但这种隐藏并不更改 Control.Paint 到 IControl.Paint 的映射,所以通过类实例和接口实例对 Paint 进行的调用就将具有不同的结果
Control c = new Control();
TextBox t = new TextBox();
IControl ic = c;
IControl it = t;
c.Paint(); // invokes Control.Paint();
t.Paint(); // invokes TextBox.Paint();
ic.Paint(); // invokes Control.Paint();
it.Paint(); // invokes Control.Paint();
但是,当接口方法被映射到类中的虚方法上时,从该类派生的类若重写了该虚方法,则将同时更改该接口的实现。例如,将上面的声明改写为
interface IControl
{
void Paint();
}
class Control: IControl
{
public virtual void Paint() {...}
}
class TextBox: Control
{
public override void Paint() {...}
}
将产生下列效果
Control c = new Control();
TextBox t = new TextBox();
IControl ic = c;
IControl it = t;
c.Paint(); // invokes Control.Paint();
t.Paint(); // invokes TextBox.Paint();
ic.Paint(); // invokes Control.Paint();
it.Paint(); // invokes TextBox.Paint();
由于显式接口成员实现不能被声明为虚的,因此不可能重写显式接口成员实现。然而,显式接口成员实现的内部完全可以调用另一个方法,只要将该方法声明为虚方法,派生类就可以重写它了。例如
interface IControl
{
void Paint();
}
class Control: IControl
{
void IControl.Paint() { PaintControl(); }
protected virtual void PaintControl() {...}
}
class TextBox: Control
{
protected override void PaintControl() {...}
}
在此,从 Control 派生的类可通过重写 PaintControl 方法来专用化 IControl.Paint 的实现。
1.1.2 接口重新实现
一个类若继承了某个接口的实现,则只要将该接口列入它的基类列表中,就可以重新实现 (re-implement) 该接口。
接口的重新实现与接口的初始实现遵循完全相同的接口映射规则。因此,继承的接口映射不会对为重新实现该接口而建立的接口映射产生任何影响。例如,在下面的声明中
interface IControl
{
void Paint();
}
class Control: IControl
{
void IControl.Paint() {...}
}
class MyControl: Control, IControl
{
public void Paint() {}
}
Control 将 IControl.Paint 映射到 Control.IControl.Paint 并不影响 MyControl 中的重新实现,该重新实现将 IControl.Paint 映射到 MyControl.Paint。
继承的公共成员声明和继承的显式接口成员声明可以参与重新实现接口的接口映射过程。例如
interface IMethods
{
void F();
void G();
void H();
void I();
}
class Base: IMethods
{
void IMethods.F() {}
void IMethods.G() {}
public void H() {}
public void I() {}
}
class Derived: Base, IMethods
{
public void F() {}
void IMethods.H() {}
}
在此,Derived 中 IMethods 的实现将接口方法映射到 Derived.F、Base.IMethods.G、Derived.IMethods.H 和 Base.I。
当类实现接口时,它还隐式实现该接口的所有基接口。与此类似,接口的重新实现也同时隐式地对该接口的所有基接口进行重新实现。例如
interface IBase
{
void F();
}
interface IDerived: IBase
{
void G();
}
class C: IDerived
{
void IBase.F() {...}
void IDerived.G() {...}
}
class D: C, IDerived
{
public void F() {...}
public void G() {...}
}
在此,IDerived 的重新实现也重新实现 IBase,并将 IBase.F 映射到 D.F。
1.1.3 抽象类和接口
与非抽象类类似,抽象类也必须为在该类的基类列表中列出的接口的所有成员提供它自己的实现。但是,允许抽象类将接口方法映射到抽象方法上。例如
interface IMethods
{
void F();
void G();
}
abstract class C: IMethods
{
public abstract void F();
public abstract void G();
}
这里,IMethods 的实现将 F 和 G 映射到抽象方法上,这些抽象方法必须在从 C 派生的非抽象类中重写。
注意:显式接口成员实现本身不能是抽象的,但是当然允许显式接口成员实现调用抽象方法。例如
interface IMethods
{
void F();
void G();
}
abstract class C: IMethods
{
void IMethods.F() { FF(); }
void IMethods.G() { GG(); }
protected abstract void FF();
protected abstract void GG();
}
这里,从 C 派生的非抽象类被要求重写 FF 和 GG,从而提供 IMethods 的实际实现。
评论