C#教程4:抽象和接口
3/29/2025
233 阅读
一、抽象(Abstraction)
抽象是面向对象编程的核心概念,它允许我们关注对象的本质特征,忽略非必要细节。在C#中,抽象主要通过以下关键字实现:
1. abstract
关键字
- 用于声明抽象类和抽象方法
- 抽象类不能被直接实例化
- 抽象方法没有实现,必须由派生类重写
2. virtual
关键字
- 用于声明可被子类重写的方法
- 虚方法有默认实现,子类可以选择重写
3. override
关键字
- 用于重写基类的虚方法或抽象方法
- 必须与基类方法有相同的签名和返回类型
代码示例:
using System;
// 抽象类:形状Shape
public abstract class Shape
{
// 普通属性
public string Color { get; set; }
// 普通方法
public void SetColor(string color)
{
Color = color;
Console.WriteLine($"设置颜色为:{color}");
}
// 虚方法:有默认实现,子类可以选择重写
public virtual void Display()
{
Console.WriteLine($"这是一个{Color}色的形状");
}
// 抽象方法:没有实现,子类必须重写
public abstract double CalculateArea();
}
// 具体类:圆形
public class Circle : Shape
{
public double Radius { get; set; }
public Circle(double radius)
{
Radius = radius;
}
// 重写抽象方法
public override double CalculateArea()
{
return Math.PI * Radius * Radius;
}
// 重写虚方法
public override void Display()
{
Console.WriteLine($"这是一个{Color}色的圆,半径为{Radius}");
}
}
// 具体类:矩形
public class Rectangle : Shape
{
public double Width { get; set; }
public double Height { get; set; }
public Rectangle(double width, double height)
{
Width = width;
Height = height;
}
// 重写抽象方法
public override double CalculateArea()
{
return Width * Height;
}
// 重写虚方法
public override void Display()
{
Console.WriteLine($"这是一个{Color}色的矩形,宽为{Width},高为{Height}");
}
}
class Program
{
static void Main(string[] args)
{
// Shape shape = new Shape(); // 错误!抽象类不能被实例化
Circle circle = new Circle(5);
circle.SetColor("红");
circle.Display();
Console.WriteLine($"圆的面积:{circle.CalculateArea():F2}");
Rectangle rectangle = new Rectangle(4, 6);
rectangle.SetColor("蓝");
rectangle.Display();
Console.WriteLine($"矩形的面积:{rectangle.CalculateArea():F2}");
// 使用多态
Shape shape1 = new Circle(3);
shape1.SetColor("绿");
shape1.Display(); // 调用Circle的Display方法
Console.WriteLine($"形状1的面积:{shape1.CalculateArea():F2}");
Console.ReadKey();
}
}
二、接口(Interface)
接口定义了一组相关功能的规范,是一种"能力"的抽象。
接口的特点:
- 使用
interface
关键字定义 - 只包含方法、属性、事件或索引器的签名,不包含实现(C# 8.0之前)
- 一个类可以实现多个接口
- 接口成员默认为public
代码示例:
using System;
// 定义接口:可绘制的
public interface IDrawable
{
void Draw();
string Description { get; }
}
// 定义接口:可移动的
public interface IMovable
{
void MoveTo(int x, int y);
int X { get; set; }
int Y { get; set; }
}
// 实现单个接口
public class Text : IDrawable
{
public string Content { get; set; }
public string Description => $"文本:{Content}";
public void Draw()
{
Console.WriteLine($"绘制文本:{Content}");
}
}
// 实现多个接口
public class Button : IDrawable, IMovable
{
public string Label { get; set; }
public int X { get; set; }
public int Y { get; set; }
public string Description => $"按钮:{Label} 位置:({X},{Y})";
public void Draw()
{
Console.WriteLine($"绘制按钮:{Label} 在位置 ({X},{Y})");
}
public void MoveTo(int x, int y)
{
X = x;
Y = y;
Console.WriteLine($"移动按钮到位置 ({X},{Y})");
}
}
class Program
{
static void Main(string[] args)
{
// 创建对象
Text text = new Text { Content = "Hello World" };
Button button = new Button { Label = "确定", X = 10, Y = 20 };
// 调用方法
text.Draw();
Console.WriteLine(text.Description);
button.Draw();
button.MoveTo(30, 40);
Console.WriteLine(button.Description);
// 使用接口类型
Console.WriteLine("\n使用接口类型:");
IDrawable[] drawables = new IDrawable[] { text, button };
foreach (IDrawable drawable in drawables)
{
drawable.Draw();
Console.WriteLine(drawable.Description);
}
// 接口转换
foreach (IDrawable drawable in drawables)
{
if (drawable is IMovable movable)
{
movable.MoveTo(100, 100);
}
}
Console.ReadKey();
}
}
三、抽象类与接口的对比
特性 | 抽象类 | 接口 |
---|---|---|
关键字 | abstract |
interface |
实例化 | 不能 | 不能 |
实现方法 | 可以包含实现的方法和抽象方法 | 只定义方法签名(C# 8.0前) |
继承/实现 | 一个类只能继承一个抽象类 | 一个类可以实现多个接口 |
访问修饰符 | 可以使用各种访问修饰符 | 成员默认为public |
字段 | 可以包含字段 | 不能包含字段 |
构造函数 | 可以包含构造函数 | 不能包含构造函数 |
静态成员 | 可以包含静态成员 | 不能包含静态成员(C# 8.0前) |
四、何时使用抽象类与接口?
使用抽象类的场景:
- 当几个相关的类需要共享代码和数据时
- 当需要定义一个基本行为,但部分行为必须由子类来实现时
- 当需要在类之间共享非public成员时
使用接口的场景:
- 当不相关的类需要共享一个行为时
- 当需要支持多重继承时
- 当只关心对象能做什么,而不关心如何做时
五、课后作业
作业1:抽象类应用
创建一个表示电器的抽象类Appliance
,包含以下内容:
- 属性:
Brand
、Model
、PowerStatus
(开/关) - 方法:
TurnOn()
、TurnOff()
- 抽象方法:
UseFunction()
然后创建至少两个继承自Appliance
的具体电器类(如Television
、Refrigerator
),实现各自的UseFunction()
方法,并在主程序中演示使用。
作业2:接口应用
设计一个简单的音乐播放系统:
- 创建接口
IPlayable
,包含方法Play()
、Pause()
、Stop()
和属性Duration
- 创建接口
IRecordable
,包含方法StartRecording()
、StopRecording()
- 创建至少两个类实现这些接口(如
MusicPlayer
只实现IPlayable
,VoiceRecorder
实现两个接口) - 在主程序中创建这些对象并通过接口类型调用它们的方法
评论 (0)
暂无评论,来发表第一条评论吧!