C#的抽象类和方法,重载,覆盖,隐藏
在C#程序中,如果不在父类的方法中添加virtual、abstract或者override描述符,那么编译器就会认为你不想在子类中覆 盖这个方法。如果我们同时去掉Children类中GetNumber()方法的override描述符,程序可以编译通过,但是这时就不是覆盖了,而是 C#中的“隐藏”关系。“隐藏”和“覆盖”具体区别就是,如果是“隐藏”,那么在通过Father类型的引用调用一个Children对象的 GetNumber()方法的时候,实际执行的部分是父类中的GetNumber()方法,而不是子类的。
因此,可以简单的这么理解,“覆盖”就是重新实现了父类的方法,而“隐藏”只是把父类中的方法藏了起来,通过父类的引用来调用这个方法的时候,这个被“隐藏”的方法就被激活了。
Code
1 //第四例 C#的抽象类和方法,重载,覆盖,隐藏
2
3
4 using System;
5
6 namespace testClassApp
7 {
8 /// <summary>
9 /// Class1 的摘要说明。
10 /// </summary>
11 class Class1
12 {
13 /// <summary>
14 /// 应用程序的主入口点。
15 /// </summary>
16 [STAThread]
17 static void Main(string[] args)
18 {
19 //
20 // TODO: 在此处添加代码以启动应用程序
21 //
22
23 double len = 2.5;
24 double wid = 3.0;
25 double rad = 4.1;
26 Rectangle aRect = new Rectangle();
27 aRect.length = len;
28 aRect.width = wid;
29 Circle aCirc = new Circle (rad);
30 Console.WriteLine ("Area of Rect is:{0}",aRect.Area ());
31 Console.WriteLine ("Area of Circ is:{0}",aCirc.Area ());
32 }
33 }
34
35 abstract class Shape //抽象基类,不可实例化
36 /* 1)声明一个抽象类使用abstract关键字
37 * 2)只要包含抽象方法的类就是抽象类(哪怕只有一个),当一个抽象类中所有的方法都是抽象时,我们就可以定义成接口
38 * 一个类可以包含一个或多个抽象方法
39 * 3)抽象类中可以存在非抽象的方法(方法可以有具体的实现)
40 * 4)抽象类不能被实例化
41 * 5)实现抽象类用":",实现抽象方法用override关键字
42 * 6)抽象类可以被抽象类所继承,结果仍是抽象类
43 * 7)抽象方法被实现后,不能更改修饰符
44 */
45 {
46 public const double pi=3.14; //常量
47 protected double x, y; //私有,可继承变量
48 //构造函数
49 /*
50 1)对象最初对对象进行实例化的过程叫做构造阶段,这个过程就是由构造函数完成的,构造函数就是用于初始化数据的函数。
51 2)所有的对象(类)都有一个默认的构造函数,没有参数,与类同名,但一个类可以包含几个带参数的构造函数
52 称为非默认的构造函数。
53 3)构造函数用new关键字来调用,例如:
54 * 调用默认构造函数:类名类的实例名= new 类名();
55 * 调用非默认构造函数:类名类的实例名= new 类名(参数);
56 * 4)构造函数与字段,属性,方法一样,可以使公共或者私有的
57 * 5)构造函数只是在对象被建立时调用,就是一句代码也不写或没有实现构造函数,那么这个类也会建立,
58 * 这个函数只是说在对象在建立的时候给了一个给这个对象初始设置值的机会
59 */
60 public Shape() //默认构造函数
61 {
62 x=y=0;
63 }
64 public Shape(double x,double y) //带参数构造函数
65 {
66 this.x = x;
67 this.y = y;
68 }
69 public abstract double Area(); //抽象方法,需重载
70 /*
71 * 1)声明一个抽象方法使用abstract关键字,抽象方法只包含方法定义,但没有具体实现的方法,需要其子类或者子类的子类来具体实现
72 * 2)子类继承抽象父类后,可以使用override关键字覆盖父类中的抽象方法,并做具体的实现。也可以不实现抽象方法,留给后代实现,
73 * 这时子类仍旧是一个抽象类,必须声明为abstract
74 * 3)继承的抽象方法不可以被隐藏
75 */
76 }
77
78 class Rectangle: Shape
79 {
80 public Rectangle():base(){}
81 public Rectangle(double x, double y): base(x,y){}//使用基类构造函数
82 /*
83 1) 隐式调用基类构造函数:如果没有明确指明base()( 即不使用base() ),子类会自动调用基类的默认构造器
84 2) 显示调用:上面的就是显示调用,使用base(参数)
85 */
86 public override double Area() //函数覆盖,子类继承抽象父类后,可以使用override关键字覆盖父类中的抽象方法,并做具体的实现。
87 //也可以不实现抽象方法,留给后代实现,
88 {
89 return (x*y);
90 }
91 public double length //属性:矩形长度
92 {
93 get
94 {
95 return x;
96 }
97 set
98 {
99 if (value>0){x = value;}
100 }
101 }
102 public double width //属性:矩形宽度
103 {
104 get
105 {
106 return y;
107 }
108 set
109 {
110 if (value>0){y = value;}
111 }
112 }
113
114 }
115
116 class Ellipse: Shape
117 {
118 public Ellipse(double x, double y):base(x,y){}//使用基类Shape的构造函数
119 public override double Area() //函数覆盖
120 {
121 return pi*x*y;
122 }
123 }
124 class Circle: Ellipse
125 {
126 public Circle(double r):base(r,0){} //使用基类Ellipse的构造函数
127 public override double Area() //函数覆盖
128 {
129 return pi*x*x;
130 }
131 }
132 //隐藏:在子类中创建与父类中的方法具有相同签名(相同的方法名,相同的参数列表-参数类型和次序)的方法(可以带有"virtual"或"override"关键字)即可实现,但建议使用"new"关键字,以明确地隐藏。
133 //只能使用"override"关键字来覆盖(override)父类中标记为"virtual"、"abstract"或"override"的方法,而子类中标记为override的方法,也必须是父类中标记为"virtual"、"abstract"或"override"的方法。
134 //覆盖(override):必须使用override关键字,可以被覆盖的方法包括标记为abstract,virtual,和override的方法;
135 //隐藏:使用new关键字,也可不使用关键字,可以被隐藏的方法包括一般方法,和标记为virtual"或"override"的方法;
136 //重载(overload):不需要任何特殊的关键字
137 //静态方法可以被隐藏或重载
138
139 /*重载,覆盖,隐藏之间的区别
140
141 重载(overload)用于同一类中的成员函数,其特征为:
142 * 1)在同一类中
143 * 2)相同的函数名
144 * 3)参数不同(包括参数类型不同,或参数个数不同,或两者都不同,注意:和返回值没关系)
145 * 4)和是否虚函数无关
146
147 覆盖(override)是指派生类函数覆盖基类函数,其特征为:
148 * 1)不同的范围(分别位于派生类与基类)
149 * 2)相同的函数名称
150 * 3)参数相同
151 * 4)基类函数必须是虚函数
152
153 隐藏(hide)是指派生类的函数屏蔽了与其同名的基类函数,其特征为:
154 * 1)不同的范围(分别位于派生类与基类)
155 * 2)相同的函数名
156
157 * 若参数不同,基类函数无virtual关键字,基类函数将会被隐藏。(因为派生类和基类不在同一范围,所以是隐藏而不是重载);
158 * 若参数不同,基类函数有virtual关键字。基类函数将会被隐藏。(因为派生类和基类不在同一范围,所以是隐藏而不是重载;因为参数不同,所以是隐藏而不是覆盖);
159 * 若参数相同,基类函数无virtual关键字。基类函数将会被隐藏。(因为基类函数不是虚函数,所以是隐藏而不是覆盖)。
160 * 若参数相同,基类函数有virtual关键字。如果基类函数有多个重载版本,且派生类并没有重写所有的同名虚函数,当在派生类中调用函数时,基类中未被重写的虚函数将被隐藏。(当然,被重写的函数就是覆盖了)。
161 注意: 如果想在派生类中调用基类中的被隐藏的函数,可以在派生类中填写如下代码:using Base::Fun2
162 */
163 }
164
1 //第四例 C#的抽象类和方法,重载,覆盖,隐藏
2
3
4 using System;
5
6 namespace testClassApp
7 {
8 /// <summary>
9 /// Class1 的摘要说明。
10 /// </summary>
11 class Class1
12 {
13 /// <summary>
14 /// 应用程序的主入口点。
15 /// </summary>
16 [STAThread]
17 static void Main(string[] args)
18 {
19 //
20 // TODO: 在此处添加代码以启动应用程序
21 //
22
23 double len = 2.5;
24 double wid = 3.0;
25 double rad = 4.1;
26 Rectangle aRect = new Rectangle();
27 aRect.length = len;
28 aRect.width = wid;
29 Circle aCirc = new Circle (rad);
30 Console.WriteLine ("Area of Rect is:{0}",aRect.Area ());
31 Console.WriteLine ("Area of Circ is:{0}",aCirc.Area ());
32 }
33 }
34
35 abstract class Shape //抽象基类,不可实例化
36 /* 1)声明一个抽象类使用abstract关键字
37 * 2)只要包含抽象方法的类就是抽象类(哪怕只有一个),当一个抽象类中所有的方法都是抽象时,我们就可以定义成接口
38 * 一个类可以包含一个或多个抽象方法
39 * 3)抽象类中可以存在非抽象的方法(方法可以有具体的实现)
40 * 4)抽象类不能被实例化
41 * 5)实现抽象类用":",实现抽象方法用override关键字
42 * 6)抽象类可以被抽象类所继承,结果仍是抽象类
43 * 7)抽象方法被实现后,不能更改修饰符
44 */
45 {
46 public const double pi=3.14; //常量
47 protected double x, y; //私有,可继承变量
48 //构造函数
49 /*
50 1)对象最初对对象进行实例化的过程叫做构造阶段,这个过程就是由构造函数完成的,构造函数就是用于初始化数据的函数。
51 2)所有的对象(类)都有一个默认的构造函数,没有参数,与类同名,但一个类可以包含几个带参数的构造函数
52 称为非默认的构造函数。
53 3)构造函数用new关键字来调用,例如:
54 * 调用默认构造函数:类名类的实例名= new 类名();
55 * 调用非默认构造函数:类名类的实例名= new 类名(参数);
56 * 4)构造函数与字段,属性,方法一样,可以使公共或者私有的
57 * 5)构造函数只是在对象被建立时调用,就是一句代码也不写或没有实现构造函数,那么这个类也会建立,
58 * 这个函数只是说在对象在建立的时候给了一个给这个对象初始设置值的机会
59 */
60 public Shape() //默认构造函数
61 {
62 x=y=0;
63 }
64 public Shape(double x,double y) //带参数构造函数
65 {
66 this.x = x;
67 this.y = y;
68 }
69 public abstract double Area(); //抽象方法,需重载
70 /*
71 * 1)声明一个抽象方法使用abstract关键字,抽象方法只包含方法定义,但没有具体实现的方法,需要其子类或者子类的子类来具体实现
72 * 2)子类继承抽象父类后,可以使用override关键字覆盖父类中的抽象方法,并做具体的实现。也可以不实现抽象方法,留给后代实现,
73 * 这时子类仍旧是一个抽象类,必须声明为abstract
74 * 3)继承的抽象方法不可以被隐藏
75 */
76 }
77
78 class Rectangle: Shape
79 {
80 public Rectangle():base(){}
81 public Rectangle(double x, double y): base(x,y){}//使用基类构造函数
82 /*
83 1) 隐式调用基类构造函数:如果没有明确指明base()( 即不使用base() ),子类会自动调用基类的默认构造器
84 2) 显示调用:上面的就是显示调用,使用base(参数)
85 */
86 public override double Area() //函数覆盖,子类继承抽象父类后,可以使用override关键字覆盖父类中的抽象方法,并做具体的实现。
87 //也可以不实现抽象方法,留给后代实现,
88 {
89 return (x*y);
90 }
91 public double length //属性:矩形长度
92 {
93 get
94 {
95 return x;
96 }
97 set
98 {
99 if (value>0){x = value;}
100 }
101 }
102 public double width //属性:矩形宽度
103 {
104 get
105 {
106 return y;
107 }
108 set
109 {
110 if (value>0){y = value;}
111 }
112 }
113
114 }
115
116 class Ellipse: Shape
117 {
118 public Ellipse(double x, double y):base(x,y){}//使用基类Shape的构造函数
119 public override double Area() //函数覆盖
120 {
121 return pi*x*y;
122 }
123 }
124 class Circle: Ellipse
125 {
126 public Circle(double r):base(r,0){} //使用基类Ellipse的构造函数
127 public override double Area() //函数覆盖
128 {
129 return pi*x*x;
130 }
131 }
132 //隐藏:在子类中创建与父类中的方法具有相同签名(相同的方法名,相同的参数列表-参数类型和次序)的方法(可以带有"virtual"或"override"关键字)即可实现,但建议使用"new"关键字,以明确地隐藏。
133 //只能使用"override"关键字来覆盖(override)父类中标记为"virtual"、"abstract"或"override"的方法,而子类中标记为override的方法,也必须是父类中标记为"virtual"、"abstract"或"override"的方法。
134 //覆盖(override):必须使用override关键字,可以被覆盖的方法包括标记为abstract,virtual,和override的方法;
135 //隐藏:使用new关键字,也可不使用关键字,可以被隐藏的方法包括一般方法,和标记为virtual"或"override"的方法;
136 //重载(overload):不需要任何特殊的关键字
137 //静态方法可以被隐藏或重载
138
139 /*重载,覆盖,隐藏之间的区别
140
141 重载(overload)用于同一类中的成员函数,其特征为:
142 * 1)在同一类中
143 * 2)相同的函数名
144 * 3)参数不同(包括参数类型不同,或参数个数不同,或两者都不同,注意:和返回值没关系)
145 * 4)和是否虚函数无关
146
147 覆盖(override)是指派生类函数覆盖基类函数,其特征为:
148 * 1)不同的范围(分别位于派生类与基类)
149 * 2)相同的函数名称
150 * 3)参数相同
151 * 4)基类函数必须是虚函数
152
153 隐藏(hide)是指派生类的函数屏蔽了与其同名的基类函数,其特征为:
154 * 1)不同的范围(分别位于派生类与基类)
155 * 2)相同的函数名
156
157 * 若参数不同,基类函数无virtual关键字,基类函数将会被隐藏。(因为派生类和基类不在同一范围,所以是隐藏而不是重载);
158 * 若参数不同,基类函数有virtual关键字。基类函数将会被隐藏。(因为派生类和基类不在同一范围,所以是隐藏而不是重载;因为参数不同,所以是隐藏而不是覆盖);
159 * 若参数相同,基类函数无virtual关键字。基类函数将会被隐藏。(因为基类函数不是虚函数,所以是隐藏而不是覆盖)。
160 * 若参数相同,基类函数有virtual关键字。如果基类函数有多个重载版本,且派生类并没有重写所有的同名虚函数,当在派生类中调用函数时,基类中未被重写的虚函数将被隐藏。(当然,被重写的函数就是覆盖了)。
161 注意: 如果想在派生类中调用基类中的被隐藏的函数,可以在派生类中填写如下代码:using Base::Fun2
162 */
163 }
164