原文链接
版权声明:本文为CSDN博主「AI浩」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
正文
密封类
通过在类定义前面放置关键字 sealed,可以将类声明为密封类。例如:
public sealed class D
{
// Class members here.
}
密封类不能用作基类。因此,它也不能是抽象类。密封类禁止派生。
由于密封类从不用作基类,所以有些运行时优化可以使对密封类成员的 调用略快。
重写基类虚成员的派生类成员,如方法、字段、属性或事件,可被声明为密封成员。
在后续的派生类中,这将取消该成员的虚效果。方法是在类成员声明中将 sealed 关键字置于 override 关键字的前面。例如:
public class D : C
{
public sealed override void DoWork() { }
}
一、特点
- 使用
sealed关键字来定义密封类。 - 密封类 不能 被继承。
- 在密封类 不能 定义虚函数,不能 定义抽象函数。
- 可以使用
sealed关键字来密封方法,但是 只有 在覆盖基类的方法时才能使用sealed关键字。 - 使用
sealed关键字密封的方法 不能 被覆盖,防止派生类进一步重写该方法,但能被重载,能被隐藏。 - 在使用
sealed关键字时,不能 同时使用abstract或virtual关键字。
注意事项:
- 密封类不能作为基类被继承,但它可以继承别的类或接口。
- 在密封类中不能声明 受保护 成员或 虚 方法,因为受保护成员和只能从派生类进行访问,而虚成员只能在派生类中重写。
- 由于密封类的不可继承性,因此密封类不能声明 抽象 的。
二、示例
using System;
using System.Collections.Generic;
using System.Text;
namespace TestSealedClass_01
{
// 密封类 不能被继承
sealed class A
{
public void Method1()
{}
//错误,在密封类中不能定义虚函数
//public virtual void Method2()
//{}
//错误,在密封类中不能定义抽象函数
//public abstract void Method3();
}
//class B : A //错误,密封类 A 不能被继承
//{}
class AutoMobile
{
public virtual void Display()
{
Console.WriteLine("这是基类 AutoMobile");
}
//Display() 方法不是重写,所以不能使用 sealed 关键字
//public sealed void Display()
//{
// Console.WriteLine("这是基类 AutoMobile");
//}
}
class Car : AutoMobile
{
//使用 sealed 关键字来密封方法
public sealed override void Display()
{
Console.WriteLine("这是派生类 Car");
}
public void Display(string mark) //使用 sealed 关键字密封的方法,能被重载
{
Console.WriteLine("这是派生类 Car:{0}", mark);
}
}
class SmallCar : Car
{
//使用 sealde 关键字密封的方法,不能被覆盖
//public override void Display()
//{}
//使用 sealde 关键字密封的方法,能被隐藏
public new void Display()
{ Console.WriteLine("这是派生类 Car"); }
}
class Program
{
static void Main(string[] args)
{
Car car = new Car();
car.Display();
}
}
}
C# 中 abstract 和 virtual 的区别
C# 中 abstract 和 virtual 比较容易混淆,都与继承有关,并且涉及 override 的使用。下面讨论一下二者的区别:
一、virtual 方法(虚方法)
virtual 关键字用于在基类中修饰方法。
virtual 的使用会有两种情况:
- 情况1:在基类中定义了
virtual方法,但在派生类中没有重写该虚方法。那么在对派生类实例的调用中,该虚方法使用的是基类定义的方法。 - 情况2:在基类中定义了
virtual方法,然后在派生类中使用override重写该方法。那么在对派生类实例的调用中,该虚方法使用的是派生重写的方法。
二、abstract 方法(抽象方法)
abstract 关键字只能用在 抽象类 中修饰方法,并且没有具体的实现。抽象方法的实现 必须 在派生类中使用 override 关键字来实现。
接口和抽象类最本质的区别:
- 抽象类是一个不完全的类,是对对象的抽象,
- 而接口是一种行为规范。
三、相关关键字
static
当一个方法被声明为 static 时,这个方法是一个静态方法,编译器会在编译时保留这个方法的实现。也就是说,这个方法属于类,但是不属于任何成员,不管这个类的实例是否存在,它们都会存在。就像入口函数 static void main,因为它是静态函数,所以可以直接被调用。
virtual
当一个方法被声明为 virtual 时,它是一个虚拟方法,直到你使用 ClassName variable = new ClassName(); 声明一个类的实例之前,它都不存在于真实的内存空间中。这个关键字在类的继承中非常常用,用来提供类方法的多态性支持。
abstract
抽象方法声明使用,是 必须 被派生类覆写的方法,抽象类就是用来被继承的;可以看成是没有实现体的虚方法;如果类中包含抽象方法,那么类就 必须 定义为抽象类,不论是否还包含其他一般方法;抽象类不能有实体的。
override
是在子类中重写父类中的方法,两个函数的函数特征(函数名、参数类型与个数)相同。用于扩展或修改继承的方法、属性、索引器或事件的抽象或虚拟实现。提供从基类继承的成员的新实现,而通过 override 声明重写的方法称为基方法。
注意事项:
- 重写基方法必须具有与
override方法相同的签名。override声明不能更改virtual方法的可访问性,且override方法与virtual方法必须具有相同级别访问修饰符。- 不能用
new、static、virtual修饰符修改override方法。- 重写属性声明必须指定与继承的属性完全相同的访问修饰符、类型和名称。
- 重写的属性必须是
virtual、abstract或override。- 不能重写非虚方法或静态方法。
- 父类中有
abstract,那么子类同名方法必定有override,若父类中有virtual方法,子类同名方法不一定是override,可能是overload。override必定有父子类关系。
overload
在 同一个类 中 方法名 相同、参数 或 返回值 不同 的多个方法即为方法重载。
注意事项:
- 出现在同一个类中。
- 参数列表不同或返回类型和参数列表都不同,只有返回类型不同不能重载。(参数列表包括参数个数和参数类型)
overwrite
用 new 实现。在子类中用 new 关键字修饰定义的与父类中 同名 的方法,也称为覆盖,覆盖不会改变父类方法的功能。