抽象类不能实例化,只能被继承;含abstract方法的类必须声明为abstract,且抽象方法无实现、须由非抽象子类override重写。

抽象类在 C# 中不是用来 new 的,而是用来被继承的;只要类里有 abstract 方法,这个类就必须声明为 abstract class,否则编译直接报错。
抽象类必须用 abstract 修饰,且不能 new
你写 new Animal() 会触发编译错误:CS0144 “无法创建抽象类的实例”。抽象类存在的唯一意义是作为基类被继承。它允许你定义一部分可复用的逻辑(比如 Sleep()),同时强制子类实现关键行为(比如 MakeSound())。
-
abstract类可以有构造函数,子类初始化时会自动调用它(哪怕你不写base()) - 抽象类可以包含字段、属性、普通方法、静态成员,甚至
protected或internal成员 - 但不能用
sealed修饰抽象类——语义冲突:一个要求必须被继承,一个禁止被继承
abstract 方法没方法体,子类必须 override
声明形如 public abstract void Run(); 的方法,结尾是分号,没有 {}。它不提供任何实现,只划出契约边界。一旦父类中存在这样的方法,所有非抽象子类都必须用 override 显式实现它。
- 不能加
private——子类根本访问不到,还怎么重写? - 不能加
static或virtual——abstract已隐含virtual语义,二者重复;static属于类型而非实例,和“由子类实现”的设计目标矛盾 - 抽象方法可以是
protected,但不推荐:外部无法通过变量调用,削弱了多态价值
抽象类 vs 接口:什么时候选 abstract class
当你要共享代码实现、需要字段或构造逻辑、或者想约束继承链深度(只能单继承)时,优先考虑抽象类。例如,所有 Shape 都要记录 CreatedTime 字段、都有默认的 ToString() 实现,但面积计算必须由子类决定——这就很适合抽象类。
- 接口更适合定义“能做什么”(
IComparable、IDisposable),抽象类更适合定义“是什么+部分怎么做”(Stream、Exception) - C# 8.0+ 支持接口默认方法,但接口仍不能有字段或构造器,这点和抽象类有本质区别
- 一个类可以
: Animal, IFlyable, ISwimmable,但只能: Mammal——继承结构越清晰,越该用抽象类做骨架
容易忽略的细节:抽象类可以没有抽象方法
这是很多人卡壳的地方:abstract class Logger 完全可以不写任何 abstract 方法,只提供通用日志格式化逻辑,并用 abstract 修饰自身来防止被误实例化。编译器只检查“有没有 abstract 成员”来决定是否强制子类实现,不检查“有没有 abstract 方法”。
- 反过来,只要有一个
abstract方法,类就必须是abstract——没得商量 - 抽象子类可以不实现父类的抽象方法,但再下一级非抽象子类必须补全
- 抽象类的构造函数不能是
abstract,但它可以是protected,这是最常见也最合理的做法











