在覆盖父类的方法时,必须显式说明是在覆盖父类方法,否则相当于没有覆盖。
class Animal {
public void run() {
Console.WriteLine("animal is running");
}
}
class Dog : Animal {
public void run() {
Console.WriteLine("dog is running");
}
}
class haha {
static void Main() {
Animal dog = new Dog();
dog.run();//animal is running
Dog d = new Dog();
d.run();//dog is running
}
}
上面Dog类中的run函数有警告在编译时会有警告:警告:“Dog.run()隐藏了继承的成员Animal.run()。如果是有意隐藏,请使用关键字 new。
即便改成下面这样,结果依然没变。
class Dog : Animal {
public new void run() {
Console.WriteLine("dog is running");
}
}
下面重点来了,直接说结论。
在 C# 中,方法不允许隐式覆盖。
派生类若想覆盖基类方法必须显示声明为override
要想把函数声明为override,必须保证基类的同名方法为abstract或者virtual或者override,否则没法把函数声明为override。
这种设计思想的好处是显而易见的,它督促程序员更明确地表达自己的观点,不允许一些implicit的东西。
然而,“要显式不要隐式”跟“约定大于配置”这两个原则是否冲突呢?
抽象类不一定包含抽象方法,包含抽象方法的类必须是抽象类,也就是说,如果方法用abstract修饰,类必须用abstract修饰。
sealed和new是一对
下面看一个标准样例,这段代码是正确而标准的。
class Animal {
public virtual void run() {//将来准备override的函数,必须用virtual声明
Console.WriteLine("animal is running");
}
}
class Cat : Animal {
public sealed override void run() {//如果是覆盖基类函数,必须用override;如果不想再被覆盖,必须用sealed
Console.WriteLine("Cat is running");
}
}
class Tiger : Cat {
public new void run() {//sealed的基类函数必须用new声明,并且不允许用override声明。如果不用new声明,编译报错“不够显式,有点含蓄,C#是反对含蓄的”
Console.WriteLine("tiger is running");
}
}
class haha {
static void Main() {
Animal a = new Tiger();
a.run();//cat is running
Cat b = new Tiger();
b.run();//cat is running
Tiger c = new Tiger();
c.run();//tiger is running
}
}
只有标记为override的函数才允许标记为sealed,否则报错因为“Animal.run()”不是重写,所以无法将其密封
被标记为sealed的函数不允许再次覆盖,派生类中也就是不允许再使用override标记函数
虽然派生类中不允许override基类中的sealed了的函数,但是派生类中可以出现sealed了的同名函数,只是不允许加override,也就是说不允许再进行显示覆盖(C#中的覆盖肯定是显示覆盖,C#不存在隐式覆盖这种东西)。这时,如果不适用new关键字,会报一个警告,就是上面出现过的那个警告:
在编译时会有警告:警告:“Tiger.run()隐藏了继承的成员Cat.run()。如果是有意隐藏,请使用关键字 new。