5.4 KiB
密封函数
概念:
密封函数指的是使用 sealed 修饰的==重写成员==
在 C# 里常见写法是 sealed override
准确一点说: C# 里通常叫“密封方法”或“密封重写成员” 有些教程会说“密封函数”,初学阶段可以理解成:==不允许下一级子类继续重写的方法==
通常用法:
- 父类允许子类重写某个方法
- 某个子类重写后,认为这个实现已经定死
- 允许这个子类继续被继承
- 但不允许更下一级子类再改这个方法
语法
class 子类名 : 父类名
{
public sealed override void 方法名()
{
}
}
注意:
sealed 修饰方法时,必须和 override 一起使用
基础案例
class Animal
{
public virtual void Speak()
{
Console.WriteLine("动物叫");
}
}
class Dog : Animal
{
public sealed override void Speak()
{
Console.WriteLine("狗叫");
}
}
class Husky : Dog
{
// 这里不能再 override Speak()
}
理解:
Animal.Speak()是虚方法,允许被重写Dog.Speak()重写了父类方法Dog.Speak()又被sealed密封Husky可以继承Dog- 但
Husky不能继续重写Speak()
sealed class 和 sealed override 的区别
密封类:
sealed class Dog : Animal
{
}
含义:
整个 Dog 类不能再被继承
密封函数:
class Dog : Animal
{
public sealed override void Speak()
{
Console.WriteLine("狗叫");
}
}
含义:
Dog 类仍然可以被继承
但是 Speak() 不能再被下一级子类重写
对比:
sealed class:封住整个类sealed override:只封住某个已经重写的成员
这个点可以和密封类一起记。
为什么密封函数必须是 override
错误写法:
class Dog
{
public sealed void Speak()
{
}
}
原因:
普通方法本来就不能被 override
没有必要再用 sealed 封住
正确理解:
sealed 修饰方法时,是在说:
“这个方法原本处在可重写链条上,但从我这里开始不准继续重写”
所以它必须修饰已经重写的成员,也就是 sealed override。
多级继承案例
class A
{
public virtual void Test()
{
Console.WriteLine("A");
}
}
class B : A
{
public override void Test()
{
Console.WriteLine("B");
}
}
class C : B
{
public sealed override void Test()
{
Console.WriteLine("C");
}
}
class D : C
{
// public override void Test()
// {
// Console.WriteLine("D");
// }
}
调用:
A a = new C();
a.Test(); // C
理解:
A.Test()开启虚方法B.Test()继续重写C.Test()重写并密封D仍然可以继承C- 但
D不能再重写Test()
密封属性
sealed override 不只可以用于方法,也可以用于属性。
class Character
{
public virtual int MaxHp
{
get { return 100; }
}
}
class Boss : Character
{
public sealed override int MaxHp
{
get { return 1000; }
}
}
后续子类不能再重写 MaxHp。
和多态的关系
密封函数不会取消已有多态效果。
Animal animal = new Dog();
animal.Speak(); // 狗叫
Dog.Speak() 仍然会通过多态被调用。
sealed override 只是限制:
后续子类不能继续改这个方法
也就是说:
- 对上层父类来说,它仍然是重写后的多态方法
- 对下层子类来说,它已经不能再被重写
常见错误
错误1:普通方法前写 sealed
class A
{
public sealed void Test()
{
}
}
sealed 不能这样修饰普通方法。
错误2:只写 sealed 不写 override
class B : A
{
public sealed void Test()
{
}
}
密封重写成员必须写成 sealed override。
错误3:父类方法不是虚方法
class A
{
public void Test()
{
}
}
class B : A
{
public sealed override void Test()
{
}
}
父类方法不是 virtual / abstract / override,子类不能 override,也就不能 sealed override。
什么时候用密封函数
适合用的情况:
- 某个重写逻辑非常关键,不希望后续子类改掉
- 父类设计允许多态,但某一层子类希望终止这个方法的重写链
- 框架或基础类库中需要保证关键行为稳定
初学阶段: 先知道这个语法和作用即可 自己写练习代码时用得不多
注意
- 密封函数常见写法是
sealed override - 它只能用于已经重写的成员
- 它阻止下一级子类继续重写这个成员
- 它不会阻止当前类被继承
- 如果想阻止整个类被继承,用
sealed class - 方法、属性、索引器、事件等重写成员都可以理解这个规则
一句话记忆
==sealed override 表示这个重写到我这里为止,后面的子类不能再改。==
面试/复习时怎么说
可以这样答:
“密封函数通常指 sealed override 修饰的重写方法。
它表示当前类重写了父类的虚方法,但不允许更下一级子类继续重写。
它和密封类不同,密封类是不允许整个类被继承,而密封函数只是禁止某个重写成员继续被重写。”
引用:
- Microsoft Learn: sealed (C# Reference)
- Microsoft Learn: override (C# Reference)
#密封函数 #密封方法 #核心