review——C# (6)虚方法和覆写方法

FROM P125

  在上一节中看到,当使用基类引用访问派生类对象时,得到的是基类的成员。虚方法可以使基类的引用访问“升至”派生类内。

  可以使用基类引用调用派生类(derived class)的方法,只需满足下列条件:

  □派生类的方法和基类的方法有相同的签名返回类型

  □基类的方法使用virtual标注

  □派生类的方法使用override标注

使用方法如下例:

1     class MyBaseClass                                   //基类
2     {
3         virtual public void Print();
4     }
5     class MyDerivedClass : MyBaseClass          //派生类
6     {
7         override public void Print()
8     }    

与上一节中不同,使用基类引用调用Print方法时,方法调用被传递到派生类并执行,因为:

□基类的方法被标记为virtual

□派生类中有匹配的override方法

如下图所示,显示了一个从virtual Print方法后面开始,并指向override Print方法的箭头

具体示例如下:

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6
 7 namespace review
 8 {
 9     class MyBaseClass                           //基类
10     {
11         virtual public void Print()
12         {
13             Console.WriteLine("This is the base class.");
14         }
15     }
16     class MyDerivedClass : MyBaseClass          //派生类
17     {
18         override public void Print()
19         {
20             Console.WriteLine("This is the derived class.");
21         }
22     }
23     class Program
24     {
25         static void Main(string[] args)
26         {
27             MyDerivedClass derived = new MyDerivedClass();
28             MyBaseClass mybc = (MyBaseClass)derived;        //强制转换成基类
29             derived.Print();
30             mybc.Print();
31             Console.Read();
32         }
33     }
34 }
35 /*
36  * 输出如下:
37  * This is the derived class.
38  * This is the derived class.
39  * */

其他的一些关于virtual和override的信息有:

□覆写和被覆写的方法必须有相同的可访问性。e.g.不能是 被覆写是private 而覆写的是public

不能覆写static方法或非虚方法

□方法、属性、索引器,以及另一种成员类型事件,都可以被声明为virtual和override

Part2 覆写标记为override的方法:

覆写方法可以在继承的任何层次中出现

□当使用对象基类部分的引用调用一个覆写的方法时,方法的调用被沿派生层次上溯执行,一直到标记为override的方法的最高派生(most-derived)版本。

□如果在更高的派生级别有该方法的其他声明,但没有被标记为override,那么它们不会被调用

以以下实例来说明,其中三个类构成一个继承的层次:

MyBaseClass、MyDerivedClass和SecondDerived。其均包含名称为Print的方法,并带有相同的签名。且分别被标记为virtual、override、 override/new 分别看一下第三个类标记为这两个的结果。

 1     class MyBaseClass                           //基类
 2     {
 3         virtual public void Print()
 4         {
 5             Console.WriteLine("This is the base class.");
 6         }
 7     }
 8     class MyDerivedClass : MyBaseClass          //派生类
 9     {
10         override public void Print()
11         {
12             Console.WriteLine("This is the derived class.");
13         }
14     }
15     class SecondDerived : MyDerivedClass        //最高派生类
16     {
17         ...// Given in the following pages
18     }

1.情况1:使用override声明Print

如果把SecondDerived的Print方法声明为override,那么它会覆写方法的全部两个低派生级别的版本,如下图所示,如果一个基类的引用被用于调用Print,它会向上传递通过整个链达到类SecondDerived中的实现。

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6
 7 namespace review
 8 {
 9     class MyBaseClass                           //基类
10     {
11         virtual public void Print()
12         {
13             Console.WriteLine("This is the base class.");
14         }
15     }
16     class MyDerivedClass : MyBaseClass          //派生类
17     {
18         override public void Print()
19         {
20             Console.WriteLine("This is the derived class.");
21         }
22     }
23     class SecondDerived : MyDerivedClass        //最高派生类
24     {
25         public override void Print()
26         {
27             Console.WriteLine("This is the second derived class.");
28         }
29     }
30     class Program
31     {
32         static void Main(string[] args)
33         {
34             SecondDerived derived = new SecondDerived();
35             MyBaseClass mybc = (MyBaseClass)derived;        //强制转换成基类
36
37             derived.Print();
38             mybc.Print();
39             Console.Read();
40         }
41     }
42 }
43 /*
44  * 输出如下:
45  * This is the second derived class.
46  * This is the second derived class.
47  * */

结果是:无论Print是通过派生类调用还是通过基类调用,都会调用最高派生类中的方法。当通过基类调用时,调用被沿着继承层次向上传递。

2.情况2:使用new声明Print

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6
 7 namespace review
 8 {
 9     class MyBaseClass                           //基类
10     {
11         virtual public void Print()
12         {
13             Console.WriteLine("This is the base class.");
14         }
15     }
16     class MyDerivedClass : MyBaseClass          //派生类
17     {
18         override public void Print()
19         {
20             Console.WriteLine("This is the derived class.");
21         }
22     }
23     class SecondDerived : MyDerivedClass        //最高派生类
24     {
25         new public void Print()
26         {
27             Console.WriteLine("This is the second derived class.");
28         }
29     }
30     class Program
31     {
32         static void Main(string[] args)
33         {
34             SecondDerived derived = new SecondDerived();
35             MyBaseClass mybc = (MyBaseClass)derived;        //强制转换成基类
36
37             derived.Print();
38             mybc.Print();
39             Console.Read();
40         }
41     }
42 }
43 /*
44  * 输出如下:
45  * This is the second derived class.
46  * This is the derived class.
47  * */

结果是:当方法Print通过SecondDerived的引用调用时,SecondDerived中的方法被执行,正如所期待的那样。然而,当方法通过MyBaseClass的引用调用时,方法调用只向上传递了一级,到达类MyDerived,在那里它被执行。

本来想使用下列代码进行 virtual -> override -> new ->override 的检验

1 class ThirdDerived : SecondDerived
2     {
3         override public void Print()
4         {
5             Console.WriteLine("This is the third derived class.");
6         }
7     }

然而编译器报错为“ThirdDerived.Print()”: 继承成员“SecondDerived.Print()”未标记为 virtual、abstract 或 override,无法进行重写

不过,当试验virtual-> override->new ->virtual ->override 时却是可以的,而实际上,这个中间多出的virtual是在对之前的一系列方法进行隐藏,即这个virtual其实应该写作 new virtual。

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6
 7 namespace review
 8 {
 9     class MyBaseClass                           //基类
10     {
11         virtual public void Print()
12         {
13             Console.WriteLine("This is the base class.");
14         }
15     }
16     class MyDerivedClass : MyBaseClass          //派生类
17     {
18         override public void Print()
19         {
20             Console.WriteLine("This is the derived class.");
21         }
22     }
23     class SecondDerived : MyDerivedClass        //最高派生类
24     {
25         new public void Print()
26         {
27             Console.WriteLine("This is the second derived class.");
28         }
29     }
30     class ThirdDerived : SecondDerived
31     {
32         new virtual public void Print()
33         {
34         }
35     }
36     class FourthDerived : ThirdDerived
37     {
38         override public void Print()
39         {
40             Console.WriteLine("This is the fourth derived class.");
41         }
42     }
43     class Program
44     {
45         static void Main(string[] args)
46         {
47             FourthDerived derived = new FourthDerived();
48             MyBaseClass mybc = (MyBaseClass)derived;        //强制转换成基类
49
50             derived.Print();
51             mybc.Print();
52             Console.Read();
53         }
54     }
55 }
56 /*
57  * 输出如下:
58  * This is the fourth derived class.
59  * This is the derived class.
60  * */

综上,对覆写方法的总结为:

通过某个引用对方法进行调用时,实际执行的是从这里出发,连续的一段override覆写中的最后一个的方法。(中间不可以用virtual隔开)。

Part3 覆盖其他成员类型

以上已经描述了如何在方法上使用virtual/override,事实上,在属性事件以及索引器上也是一样的。e.g.下面的代码演示了名为MyProperty的只读属性,其中使用了virtual/override

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6
 7 namespace review
 8 {
 9     class MyBaseClass                           //基类
10     {
11         private int _mInt = 5;
12         virtual public int MyProperty
13         {
14             get { return _mInt; }
15         }
16     }
17     class MyDerivedClass : MyBaseClass          //派生类
18     {
19         private int _mInt = 10;
20         public override int MyProperty
21         {
22             get
23             {
24                 return _mInt;
25             }
26         }
27     }
28     class Program
29     {
30         static void Main(string[] args)
31         {
32             MyDerivedClass derived = new MyDerivedClass();
33             MyBaseClass mybc = (MyBaseClass)derived;        //强制转换成基类
34
35             Console.WriteLine(derived.MyProperty);
36             Console.WriteLine(mybc.MyProperty);
37             Console.Read();
38         }
39     }
40 }
41 /*
42  * 输出如下:
43  * 10
44  * 10
45  * */

这里需要注意的是,最终执行下去返回的属性就是派生类的属性。

原文地址:https://www.cnblogs.com/quintessence/p/9100751.html

时间: 2024-10-11 09:01:47

review——C# (6)虚方法和覆写方法的相关文章

C#使用基类的引用 and 虚方法和覆写方法

结论:使用基类的引用,访问派生类对象时,得到的是基类的成员. 虚方法和覆写方法

虚方法和覆写方法

using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace nange_1 { class A { public void f() { Console.WriteLine("在基类中"); } } class B : A { public void f() { Console.WriteLine("在子类中"); } } class P

方法的覆写

方法的覆写 类和父类有相同的方法,那么类中方法的访问权限不能比父类中对应方法的访问权限严格,这就叫方法的覆写,一般称之为类覆写了父类中的某个方法 覆写方法的作用:对于一个类,向上转换后(把类的实例化对象赋值给类的父类的对象),通过该父类的对象直接访问该父类的对象的本类部分中被类所覆写的方法时,将自动访问跳转到类中对应的覆写的方法 static方法的覆写不起覆写作用,原因现阶段只能解释为Java就是这样设计的 package test1; public class Test1 { public s

Java中方法的覆写

所谓方法的覆写override就是子类定义了与父类中同名的方法,但是在方法覆写时必须考虑权限,即被子类覆写的方法不能拥有比父类方法更加严格的访问权限. 修饰符分别为public.protected.default.private.他们的访问权限如下图所示. 用public修饰的类在本类.同包.子类.其他包中互相访问都是可以的. 用protected修饰的类在本类.同包.子类中互相访问都是可以的,protected不可以在包外没有继承关系的类中互相访问. 就说明用default修饰的类在本类.同包

在C#中该如何阻止虚方法的覆写

在开发过程中,我们为了让一个类更有生命力,有时会用virtual来修饰一个方法好让子类来覆写它.但是如果有更新的子子类来覆写时,我们又不想让其影响到上一层的覆写,这时候就要用到new virtual来阻断覆写了. public class Animal { public virtual void WhoAmI() { Console.WriteLine("I am Animal."); } } public class Dog : Animal { public override vo

Java中的overload(方法的覆写)

方法覆写(overload)与方法的重载非常相似,它在 Java的继承中也有很重要的应用. 写程序可能会碰到下面的情况,在父类中已经实现的方法可能不够精确,不能满足子类 的需求.例如在前面的 Animal类中,breath方法就过于简单,对于鱼类动物是用腮呼吸的, 而对于哺乳动物则是用肺呼吸的,如何实现呢,Java提供的方法覆写就是解决这方面的问题. 在下面的程序中首先定义了一个父类 Animal,然后定义 Animal的  3个子类  Tiger.Fish 和 Dog,在父类中提供了 3个方法

Java基础学习笔记【02】方法覆写、快捷键、super、this、单例模式、适配器

访问类型默认default就是默认没写访问权限,就是包下的访问权限(类内部.同一个包) 除了private访问权限本类,其他的访问权限都包括包 继承:[A继承B] 1 类名A extends 类名B 类的方法[覆写]: 方法要素 描述 方法名 子类父类的覆写方法名一致 返回值 小于父类的返回 参数 小于父类的参数类型 访问类型 大于父类的访问类型 覆写: 1 public void Fun(object obj){  } 1 2 @override public void Fun(string

类的继承,方法的重载和覆写

在网易云课堂上看到唐大仕老师讲解的关于类的继承.方法的重载和覆写的一段代码,注释比较详细,在此记下以加深理解. 小总结: 1.类的继承:同类可以实例化(Student t=new Student(),Person p=new Person()),人类可以强制转换为学生类(Student t=(Student)Person),人类可以是学生类(Person p=new Student()): 2.方法的重载:只要求方法名称相同,返回类型.参数数目和参数类型都可以不相同: 3.方法的覆写:只有基类中

JAVA中继承时方法的重载(overload)与重写/覆写(override)

JAVA继承时方法的重载(overload)与重写/覆写(override) 重载-Override 函数的方法参数个数或类型不一致,称为方法的重载. 从含义上说,只要求参数的个数或参数的类型不一致就说两个函数是重载函数,而至于返回值是否一样,没关系.同时,重载可以发生在同一个类中也可以发生在继承关系中. class A { } class B extends A { public void fun(String data1) { System.out.println(data1); } pub