C#多态依赖virtual和override实现运行时绑定:virtual声明方法可被重写并加入虚方法表,override将其注册进vtable,使基类引用调用时根据实际类型执行对应子类逻辑。

多态在 C# 中不是靠“猜类型”或“一堆 if-else”实现的,而是靠 virtual 和 override 配合运行时绑定来达成的——没这俩关键字,哪怕继承了也没用。
为什么加了 virtual 才能被重写?
因为 C# 默认所有实例方法都是“静态绑定”的:编译器在编译时就锁死了调用哪个方法体。加 virtual 是告诉编译器:“这个方法的最终实现,得等运行时看对象真实类型再决定”。
-
virtual只能修饰非private、非static、非sealed的实例方法(属性和索引器也支持) - 没加
virtual的方法,子类用override会直接编译报错:'xxx' cannot override inherited member 'yyy' because it is not marked virtual, abstract, or override - 即使父类方法是
public,子类重写时也必须保持访问修饰符一致,不能改成protected或internal
override 不是“覆盖”,是“参与虚调用链”
写 override 不只是换个函数体,而是把自己注册进该类型的虚方法表(vtable),让基类引用也能触发它。这点和 new 有本质区别。
- 用
new声明同名方法,只是“隐藏”父类方法,不进 vtable,基类引用调用时仍走父类逻辑 - 用
override后,哪怕变量声明类型是父类,只要实际是子类实例,就会执行子类版本 - 子类中若想在重写逻辑里调父类原实现,必须显式写
base.MethodName();不写就不会自动调用
构造函数里调 virtual 方法很危险
这是新手高频翻车点:父类构造函数执行时,子类字段可能还没初始化,但 virtual 方法却可能被子类 override 版本接管,导致 NullReferenceException 或未定义行为。
- 例如父类构造器里调了
Initialize()(标记为virtual),而子类重写了它并访问了自己未初始化的string _config字段 - 解决办法只有两个:要么把该方法改成非虚(
private或sealed),要么确保子类重写逻辑不依赖自身未初始化状态 - 不要指望“子类构造器先跑”——C# 是先跑父类构造器,再跑子类构造器
真正难的不是写对 virtual 和 override,而是判断哪些方法值得虚化:暴露给下游扩展的入口才需要,内部逻辑、性能敏感路径、明确不许变更的行为,都不该加 virtual。滥用会导致 vtable 膨胀、内联失效、调试路径变深——这些细节往往被忽略,但直接影响可维护性与性能。


















