文章目录
- 不可用的修饰
- 可用的修饰
- 非抽象类实现接口
- 抽象类实现接口
- 抽象类与接口方法同名时一同实现
不可用的修饰
在C#中实现接口时,我们不能直接使用static
或const
来实现接口成员,因为接口中的成员默认都是实例成员,并且它们表示一种契约,要求任何实现该接口的类都必须提供这些成员的具体实现。
可用的修饰
我们可使用关键字virtual或abstract来实现接口成员。
非抽象类实现接口
当一个非抽象类实现接口时,它必须为接口的所有成员提供具体实现,而这些方法可以直接实现或者通过virtual
关键字使其成为虚方法,以便派生类可以进一步重写(override)它们。
using System;
// 定义一个接口
interface IAnimal
{
void Eat();
void Sleep();
}
// 非抽象类实现接口
class Cat : IAnimal
{
// 同时作为接口成员实现和虚方法,允许派生类进行覆盖
public virtual void Eat()
{
Console.WriteLine("猫正在吃东西");
}
// 实现接口的Sleep方法,这里也用virtual关键字,不过不是必须的
public virtual void Sleep()
{
Console.WriteLine("猫正在睡觉");
}
}
// 派生类覆盖Eat方法
class Kitten : Cat
{
public override void Eat()
{
Console.WriteLine("小猫正在喝奶");
}
}
class Program
{
static void Main(string[] args)
{
Kitten myKitten = new Kitten();
((IAnimal)myKitten).Eat(); // 输出 "小猫正在喝奶"
myKitten.Sleep(); // 输出 "猫正在睡觉"
}
}
运行结果如下所示,Cat类是一个非抽象类,它实现了IAnimal接口。尽管在非抽象类中,接口方法默认已经是实例方法,但我们仍然可以使用virtual关键字声明Eat和Sleep方法为虚方法,这样它们就可以被派生类Kitten覆盖。
Kitten类继承自Cat类,并覆盖了Eat方法以提供特定于小猫的行为。即使Eat方法在基类中既是接口实现又是虚方法,这并不影响它在派生类中的覆盖行为。:
抽象类实现接口
在抽象类(abstract class)中实现接口时,如果抽象类选择部分实现接口(也就是只提供部分成员的实现),那么未实现的接口成员可以在抽象类中声明为abstract
,这样就强制所有继承自这个抽象类的子类去实现那些接口的未实现成员。
using System;
// 定义一个接口
interface IAnimal
{
void Eat();
void Sleep();
}
// 抽象类实现接口,部分成员使用abstract关键字让子类去实现
abstract class AnimalBase : IAnimal
{
public abstract void Eat(); // 这是抽象方法,需要子类实现
// 实现接口的Sleep方法
public virtual void Sleep()
{
Console.WriteLine("动物正在睡觉");
}
}
// 具体的子类,必须实现父类中未实现的抽象接口方法
class Dog : AnimalBase
{
public override void Eat()
{
Console.WriteLine("狗正在吃东西");
}
// 可以选择覆盖父类中的虚方法
public override void Sleep()
{
Console.WriteLine("狗正在打盹儿");
}
}
class Program
{
static void Main(string[] args)
{
Dog myDog = new Dog();
myDog.Eat(); // 输出 "狗正在吃东西"
myDog.Sleep(); // 输出 "狗正在打盹儿"
}
}
实现结果如下图所示,AnimalBase是一个抽象类,它实现了IAnimal接口。其中Eat方法被声明为abstract,意味着所有继承自AnimalBase的类都必须提供这个方法的具体实现。
同时,Sleep方法在AnimalBase中提供了默认实现,并通过virtual关键字使其成为可覆盖的虚方法。在派生类Dog中,我们选择了覆盖Sleep方法以提供更具体的实现。
抽象类与接口方法同名时一同实现
在非抽象类中,如果一个方法同时是接口实现也是基类虚方法或抽象方法(即用virtual
或abstract
修饰),这并不影响它作为接口成员的实现,也就是说,你只需要实现这个方法,那么就相当于同时实现了接口和抽象类(或虚方法),同时也允许派生类进行覆盖。
using System;
// 定义一个接口
interface IAnimal
{
void Eat();
void Sleep();
}
// 抽象类Cat,包含与接口IAnimal.Eat同名的抽象方法
abstract class Cat
{
// 与接口IAnimal中的Eat方法标签一致,声明为抽象方法
public abstract void Eat();
public abstract void Sleep();
}
// 基类KittyCat 继承自抽象类Cat并实现接口IAnimal
class KittyCat : Cat, IAnimal
{
// 实现抽象类Cat中未实现的Eat方法,同时也满足了接口IAnimal的要求
public override void Eat()
{
Console.WriteLine("小猫正在吃东西");
}
public override void Sleep()
{
Console.WriteLine("小猫正在打盹儿");
}
}
class Program
{
static void Main(string[] args)
{
KittyCat myKitty = new KittyCat();
((IAnimal)myKitty).Eat(); // 输出 "小猫正在吃东西"
myKitty.Sleep(); // 输出 "小猫正在打盹儿"
}
}
运行结果如下所示: