c# 抽象方法和虚方法的区别

来源:这里教程网 时间:2026-02-21 17:38:29 作者:

抽象方法必须定义在抽象类里,且不能有方法体

这是最硬的限制:只要写了

abstract
,就必须把整个类也标成
abstract
,否则编译直接报错。而且抽象方法声明后只能跟个分号,不能写大括号和实现逻辑。

错误写法:
public class Animal { public abstract void Speak(); }
→ 编译器会提示“非抽象类不能包含抽象成员”
正确写法:
public abstract class Animal { public abstract void Speak(); }
子类如果不
override
所有抽象方法,自己也会变成抽象类,无法
new
实例

虚方法可以存在于普通类,且必须带默认实现

virtual
方法本质是“可选覆盖的已实现方法”,它不要求继承者一定重写,也不强制父类是抽象的。

你可以直接实例化含
virtual
方法的类:
var a = new Animal(); a.Speak(); // 输出默认行为
子类不写
override
也没问题,调用时自动走基类逻辑
但注意:
virtual
不能和
private
static
abstract
同时出现 —— 这些修饰符语义冲突

重写语法一样,但约束力度天差地别

两者都用

override
,但背后意图完全不同:抽象方法是“契约”,虚方法是“建议”。

抽象方法未被重写 → 编译失败(CS0534):“类型未实现继承的抽象成员” 虚方法未被重写 → 完全合法,运行时自动回退到基类实现 想阻止子类再重写?虚方法可用
sealed override
,抽象方法做不到(因为没实现可封)

什么时候该用 abstract,什么时候该用 virtual?

看设计意图:如果某个行为在所有子类中“必然不同”,且基类根本没法提供合理默认值,就用

abstract
;如果基类能给出一个通用兜底行为,只是允许子类按需定制,就用
virtual

比如
Draw()
对图形基类:不同图形绘制逻辑完全无关 → 抽象方法更合适
比如
ToString()
GetHashCode()
:基类已有合理默认实现 → 虚方法更自然
混用常见:抽象类里既有
abstract
方法(强制实现),也有
virtual
方法(提供可选扩展点)
抽象方法不是“没写完的虚方法”,而是“故意留白的契约”;虚方法也不是“弱化的抽象方法”,而是“自带备胎的灵活接口”。漏掉这个区分,很容易在重构时把抽象类强行实例化,或在不该加
override
的地方硬塞重写逻辑。

相关推荐