ClassBase A = New ClassSon() 全面分析
先看如下的代码:
这段代码很简单,定义了一个基类和一个继承它的子类.
在面向对象的的概念中,最基础的应该就是继承了.继承概念很简单:基础类的公有元素(字段,属性,方法)可以被继承它的子类使用,就如同子类自己定义的一样,如果觉得基类定义的方法不太爽,还可以自己写一个同名的方法覆盖它,这就是所谓的重写(override),比如代码红的方法A(), 但是实现方法的重写是有条件的,基类的方法是公有,切是虚方法.那假如基类的某方法是公有但不是虚方法,而在子类中我也想重新定义呢,比如说方法B(),这时候C#就有了应藏方法的概念.即:在子类中对基类中非虚方法的另一种重写,子类在隐藏基类的方法时,可在方法前面增加一关键字 NEW(也可以不加),如子类中的方法B().
说完了重写和覆盖,看如下代码:
SonClass Me = new SonClass();
Me.str; Me.A(); Me.B();
或者:
BaseClass Base = new BaseClass ();
Base .str; Base .A(); Base .B();
输出结果一目了然,不必多费口舌.
再看如下代码:
BaseClass Me = new SonClass();
Me.str; Me.A(); Me.B();
大家就可能有点迷糊了,即使知道输出结果,但为什么是这样的输出,可能还是糊涂.我看过好几本还算不错的书,包括博客园出的一本<你必须知道的.NET>,说实话,在对这个知识点的描述上实在不敢恭维. 后来查资料有这么一段描述:如果是重写,则,如果声明的基类对象,指向的是派生类,那么这时调用的是派生类中对基类方法重写的方法,也就是说Me.A(); 执行的是SonClass类中对BaseClass.A()重写的方法,即SonClass.A(). 如果是隐藏,则,如果声明的基类对象,指向的是派生类,那么这时调用的是基类中的方法,也就是说Me.B(); 执行的是BaseClass.B(). 再看看Me.str,它调用的是类中的字段,它其实是和方法B()情况是一样的,只是没有在子类中增加关键字NEW而已.所以,Me.str调用的也是BaseClass.str.
再说一下BaseClass Me = new SonClass(); 这种基类/子类相互之间的定义引用,先让我们看看该代码表示的意思:
BaseClass Me = new SonClass(); 表示,要在堆栈中定义一个类型为BaseClass的指针变量Me,指向的是堆中具体定义的类SonClass的实例, 和该代码对应的:SonClass Me = new SonClass(); 表示要在堆栈中定义一个类型为SonClass的指针变量Me,指向的是堆中具体定义的类SonClass的实例,由此可以知道,在这两句代码执行完毕后,实例化的类都是SonClass,但代表它们的对象指针类型是不一样的,一个是BaseClass 一个是 SonClass . 就以上申明来说,申明了一个基类的变量,实际指想的是子类的一个实例.这是允许的,那反过来呢:SonClass Me = new BaseClass(); 是不允许的,打个比喻,父亲会修自行车,也会修鞋,他把这些技能传给了儿子(继承),而儿子不但掌握了父亲的这两样技能,还自学了修汽车的技能. 经过SonClass Me = new SonClass(); 之后,ME的身份就成了父亲,他对外只接受修自行车和修鞋的工作,但是实际上这些工作是由他的儿子new SonClass()来完成的,因为他只是个代表.真正工作的是儿子.他接受的工作他儿子都能完成,因为他把这些工作的技能继承给了他儿子. 那反过来呢SonClass Me = new BaseClass(); ME的身份就成了儿子,实际完成工作的是父亲,如果儿子接受了修自行车,修鞋的工作父亲还可以应付,但如果儿子接受了修汽车的工作呢?
最后再补充一下这种情况说明BaseClass Me = new SonClass(); SonClass Me1 = (SonClass )Me 是合法的,因为在这里Me 虽然是基类类型,但它实际指向的是子类BaseClass Me = new SonClass(); ,而在类型转换时SonClass Me1 = (SonClass )Me ,通过Me编译器会找到它所代表的真正实例是SonClass,而SonClass Me1 = (SonClass )Me(实际是SonClass的实例 )是合法的. 但是如果是这种情况,执行会失败:BaseClass Me = new BaseClass (); SonClass Me1 = (SonClass )Me ;原因不在赘述.
1![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
2
public class BaseClass
3
{
4
public string str = "基类的字段";
5![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
6
public virtual string A()
7
{
8
return "基类的方法A";
9
}
10![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
11
public string B()
12
{
13
return "基类的方法B";
14
}
15
}
16![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
17![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
18
public class SonClass : BaseClass
19
{
20
public string str = "子类的字段";
21![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
22
public override string A()
23
{
24
return "子类的方法A";
25
}
26![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
27
new public string B()
28
{
29
return "子类的方法B";
30
}
31
}
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
2
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
3
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
4
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
5
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
6
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
7
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
8
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
9
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
10
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
11
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
12
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
13
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
14
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
15
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
16
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
17
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
18
![](https://www.cnblogs.com/Images/OutliningIndicators/None.gif)
19
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
20
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
21
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
22
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
23
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
24
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
25
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
26
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
27
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
28
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
29
![](https://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif)
30
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif)
31
![](https://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif)
这段代码很简单,定义了一个基类和一个继承它的子类.
在面向对象的的概念中,最基础的应该就是继承了.继承概念很简单:基础类的公有元素(字段,属性,方法)可以被继承它的子类使用,就如同子类自己定义的一样,如果觉得基类定义的方法不太爽,还可以自己写一个同名的方法覆盖它,这就是所谓的重写(override),比如代码红的方法A(), 但是实现方法的重写是有条件的,基类的方法是公有,切是虚方法.那假如基类的某方法是公有但不是虚方法,而在子类中我也想重新定义呢,比如说方法B(),这时候C#就有了应藏方法的概念.即:在子类中对基类中非虚方法的另一种重写,子类在隐藏基类的方法时,可在方法前面增加一关键字 NEW(也可以不加),如子类中的方法B().
说完了重写和覆盖,看如下代码:
SonClass Me = new SonClass();
Me.str; Me.A(); Me.B();
或者:
BaseClass Base = new BaseClass ();
Base .str; Base .A(); Base .B();
输出结果一目了然,不必多费口舌.
再看如下代码:
BaseClass Me = new SonClass();
Me.str; Me.A(); Me.B();
大家就可能有点迷糊了,即使知道输出结果,但为什么是这样的输出,可能还是糊涂.我看过好几本还算不错的书,包括博客园出的一本<你必须知道的.NET>,说实话,在对这个知识点的描述上实在不敢恭维. 后来查资料有这么一段描述:如果是重写,则,如果声明的基类对象,指向的是派生类,那么这时调用的是派生类中对基类方法重写的方法,也就是说Me.A(); 执行的是SonClass类中对BaseClass.A()重写的方法,即SonClass.A(). 如果是隐藏,则,如果声明的基类对象,指向的是派生类,那么这时调用的是基类中的方法,也就是说Me.B(); 执行的是BaseClass.B(). 再看看Me.str,它调用的是类中的字段,它其实是和方法B()情况是一样的,只是没有在子类中增加关键字NEW而已.所以,Me.str调用的也是BaseClass.str.
再说一下BaseClass Me = new SonClass(); 这种基类/子类相互之间的定义引用,先让我们看看该代码表示的意思:
BaseClass Me = new SonClass(); 表示,要在堆栈中定义一个类型为BaseClass的指针变量Me,指向的是堆中具体定义的类SonClass的实例, 和该代码对应的:SonClass Me = new SonClass(); 表示要在堆栈中定义一个类型为SonClass的指针变量Me,指向的是堆中具体定义的类SonClass的实例,由此可以知道,在这两句代码执行完毕后,实例化的类都是SonClass,但代表它们的对象指针类型是不一样的,一个是BaseClass 一个是 SonClass . 就以上申明来说,申明了一个基类的变量,实际指想的是子类的一个实例.这是允许的,那反过来呢:SonClass Me = new BaseClass(); 是不允许的,打个比喻,父亲会修自行车,也会修鞋,他把这些技能传给了儿子(继承),而儿子不但掌握了父亲的这两样技能,还自学了修汽车的技能. 经过SonClass Me = new SonClass(); 之后,ME的身份就成了父亲,他对外只接受修自行车和修鞋的工作,但是实际上这些工作是由他的儿子new SonClass()来完成的,因为他只是个代表.真正工作的是儿子.他接受的工作他儿子都能完成,因为他把这些工作的技能继承给了他儿子. 那反过来呢SonClass Me = new BaseClass(); ME的身份就成了儿子,实际完成工作的是父亲,如果儿子接受了修自行车,修鞋的工作父亲还可以应付,但如果儿子接受了修汽车的工作呢?
最后再补充一下这种情况说明BaseClass Me = new SonClass(); SonClass Me1 = (SonClass )Me 是合法的,因为在这里Me 虽然是基类类型,但它实际指向的是子类BaseClass Me = new SonClass(); ,而在类型转换时SonClass Me1 = (SonClass )Me ,通过Me编译器会找到它所代表的真正实例是SonClass,而SonClass Me1 = (SonClass )Me(实际是SonClass的实例 )是合法的. 但是如果是这种情况,执行会失败:BaseClass Me = new BaseClass (); SonClass Me1 = (SonClass )Me ;原因不在赘述.