在C#的面向对象编程体系中,abstract关键字用于定义抽象类和抽象成员,是实现代码复用和多态特性的核心工具之一,它允许开发者定义包含未完成实现的类或成员,让子类去完成具体的逻辑实现。

抽象类和抽象方法的基础定义
使用abstract关键字修饰的类被称为抽象类,抽象类不能被直接实例化,只能作为基类被其他类继承。抽象类中可以包含抽象方法、普通方法、属性、字段等成员。抽象方法同样用abstract修饰,没有方法体,必须由继承该抽象类的非抽象子类重写实现。
下面是一个基础的抽象类和抽象方法定义示例:
// 定义抽象类Shape
public abstract class Shape
{
// 抽象方法,计算面积,没有方法体
public abstract double CalculateArea();
// 普通方法,抽象类中可以包含已实现的方法
public void PrintInfo()
{
Console.WriteLine("这是一个图形");
}
// 抽象属性,获取图形名称
public abstract string ShapeName { get; }
}
抽象关键字的使用规则
使用abstract关键字时需要遵循以下核心规则:
- 抽象类不能被实例化,不能使用
new关键字创建抽象类的对象 - 抽象方法只能存在于抽象类中,普通类不能定义抽象方法
- 继承抽象类的非抽象子类,必须重写抽象类中所有的抽象方法和抽象属性,除非该子类也是抽象类
- 抽象方法不能是私有的,通常定义为公共或受保护的访问级别,方便子类重写
- 抽象类可以包含构造方法,虽然不能直接实例化,但子类实例化时会调用抽象类的构造方法
抽象类的继承与实现示例
我们基于上面的Shape抽象类,定义两个子类Circle和Rectangle,实现抽象成员:
// 圆形类继承Shape抽象类
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 string ShapeName
{
get { return "圆形"; }
}
}
// 矩形类继承Shape抽象类
public class Rectangle : Shape
{
// 矩形的长和宽
public double Length { get; set; }
public double Width { get; set; }
public Rectangle(double length, double width)
{
Length = length;
Width = width;
}
// 重写抽象方法,实现面积计算
public override double CalculateArea()
{
return Length * Width;
}
// 重写抽象属性
public override string ShapeName
{
get { return "矩形"; }
}
}
调用这些类的代码示例如下:
class Program
{
static void Main(string[] args)
{
// 抽象类不能直接实例化,使用子类对象赋值给抽象类变量
Shape circle = new Circle(5);
Shape rectangle = new Rectangle(4, 6);
Console.WriteLine($"{circle.ShapeName}的面积是:{circle.CalculateArea():F2}");
circle.PrintInfo();
Console.WriteLine($"{rectangle.ShapeName}的面积是:{rectangle.CalculateArea():F2}");
rectangle.PrintInfo();
}
}
抽象类与接口的差异
很多开发者会混淆抽象类和接口的使用场景,两者的核心差异如下:
| 对比维度 | 抽象类 | 接口 |
|---|---|---|
| 定义关键字 | abstract class | interface |
| 成员实现 | 可以包含已实现的方法和未实现的抽象成员 | 只能包含未实现的成员(C# 8.0后可以有默认实现) |
| 继承限制 | 单继承,一个类只能继承一个抽象类 | 多实现,一个类可以实现多个接口 |
| 访问修饰符 | 抽象成员可以有访问修饰符 | 接口成员默认是公共的,不能加访问修饰符 |
| 适用场景 | 表示一类事物的共性,有共同的基类特征 | 定义一组行为规范,不限制类的继承体系 |
抽象关键字的使用场景
在实际开发中,abstract关键字适合用在以下场景:
- 多个类有共同的基类特征,且基类不需要被直接实例化,比如上面的图形基类,所有图形都有面积计算和名称属性,但图形本身没有具体实例
- 需要定义一套统一的规范,同时提供部分通用实现,减少子类的重复代码
- 希望强制子类必须实现某些方法,避免子类遗漏核心逻辑的实现
如果基类没有通用的实现逻辑,只需要定义规范,那么更适合使用接口;如果基类有通用的实现,同时需要子类补充特定逻辑,抽象类是更好的选择。