抽象方法必须定义在抽象类里,且不能有方法体
这是最硬的限制:只要写了
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的地方硬塞重写逻辑。
