抽象类不能被实例化,必须通过继承实现其抽象方法;抽象方法无实现体且强制子类重写;抽象类可混用普通、虚和抽象成员;sealed与abstract互斥。

抽象类不能被 new 出来,这是它最直接的约束,也是你写错时编译器第一个报错的地方。
abstract class 声明后立刻生效的限制
一旦类加了 abstract 关键字,它就失去被实例化的资格。哪怕里面全是普通方法、字段,只要声明为 abstract class,下面这行代码就会编译失败:
var a = new MyAbstractClass(); // CS0144: 无法创建抽象类的实例
这不是运行时检查,是编译期硬性拦截。常见误操作包括:
- 在工厂方法或 DI 容器注册时直接注册抽象类(如
services.AddSingleton<myabstractclass>()</myabstractclass>) - 单元测试里试图 new 抽象类来测基类逻辑(应改用具体子类或 mock)
- 把抽象类当接口用,以为“只是没实现而已”,忽略了语义上它是“不完整的基类”
abstract 方法必须被 override 实现,且不能带方法体
抽象方法本质是契约:基类不提供实现,但强制所有非抽象子类补上。它和 virtual + override 的组合有本质区别——前者是“必须实现”,后者是“可选重写”。
注意几个关键点:
- 抽象方法只能出现在
abstract class中,普通类里写public abstract void Foo();直接报错 - 声明时结尾必须是分号,不能有
{}或=>,否则编译器提示 CS0502:“成员不能同时是 abstract 和 sealed”(隐含了你写了实现) - 子类实现时必须用
public override(或protected override等可见性一致/更宽的修饰符),仅写public void Foo()不算重写,会编译失败
示例片段:
abstract class Animal { public abstract void Speak(); }
class Dog : Animal { public override void Speak() { Console.WriteLine("Woof"); } } // ✅
class Cat : Animal { public void Speak() { Console.WriteLine("Meow"); } } // ❌ 缺少 override
抽象类可以混用普通成员与抽象成员
抽象类不是“全抽象”的容器,它可以同时包含:
- 已实现的普通方法(供子类直接复用)
- 虚方法(
virtual,子类可选择override) - 抽象方法(
abstract,子类必须override) - 字段、属性、构造函数(注意:子类构造函数需显式调用
base(...))
这种混合设计很实用,比如定义一个数据处理基类:
abstract class DataProcessor {
protected string SourcePath { get; set; }
public void Preprocess() { /* 通用预处理逻辑 */ }
public virtual void Validate() { /* 默认校验,可被重写 */ }
public abstract void Execute(); // 子类必须决定怎么执行
}
性能上无额外开销——抽象方法调用和虚方法一样走 vtable,但语义更严格;兼容性上从 .NET Framework 1.0 就完全支持,无版本顾虑。
sealed class 和 abstract class 是互斥的
你不能同时写 public abstract sealed class C,编译器会直接拒绝。因为二者语义冲突:
-
abstract意味着“必须被继承”,否则毫无意义 -
sealed意味着“禁止被继承”,彻底封死扩展路径
实际开发中容易踩的坑是:在重构时先加了 sealed 防止误继承,后来又想抽公共逻辑到基类,顺手加 abstract,结果编译不过。这时候得二选一:要么去掉 sealed 让它可继承,要么放弃抽象化,用组合代替继承。
真正需要警惕的是“抽象类里塞了密封方法”——public abstract sealed override void M() 这种写法根本不存在,sealed 只能修饰 override 方法,不能修饰 abstract 方法本身。











