继承多态绕点 C#篇

时间:2024-12-25 16:35:57

最近在看博客的时候看到一块很绕的地方,有点类似于以前学习C语言是的i++,++i组合到一起使用的情况,很坑b的,绝对会比i++,++i这种情况更有用,虽然实际代码里面确实很少出现.

面对象像三大特点不是封装,继承和多态吗,绕的地方主要是继承和多态融合到一起的时候.不啰嗦,先看下面代码

    public class Shape { }
public class Rectangle : Shape { }
public class Triangle : Shape { } public class Father
{
public void Foo(Rectangle r)
{
Console.WriteLine("Father Foo(Rectangle)");
}
public virtual void Foo(Triangle t)
{
Console.WriteLine("Father Foo(Triangle)");
}
} public class Son : Father
{
public void Foo(Shape s)
{
Console.WriteLine("Son Foo(Shape)");
}
public override void Foo(Triangle t)
{
Console.WriteLine("Son override Foo(Triangle)");
}
}

上面三个类是 矩形,三角形 继承 形状,下面两个类是 父亲 有两个方法,一个参数Rectangle的,一个参数Triangle的(这个是虚的),儿子类,一个Shape的方法,一个Triangle的重写方法,这里没有添加一个Rectangle的方法,因为添加了就会覆盖父新的方法.
理论上现在父亲的对象有两个方法,儿子的对象有三个方法,因为有一个Rectangle的方法继承至父亲.那么看下下面代码输出情况

        Shape s = new Shape();
Rectangle r = new Rectangle();
Triangle t = new Triangle(); Father fa = new Son();
Son so = new Son(); fa.Foo(r);//
fa.Foo(t); so.Foo(s);//
so.Foo(r);
so.Foo(t);

我们先猜一下//1,//2部分出输什么结果,然后再看一下运行的结果

//
Father Foo(Rectangle)
Son override Foo(Triangle)
//
Son Foo(Shape)
Son Foo(Shape)
Son Foo(Shape)

我们来看一下是否有绕的地方,//1
第1行 fa调Rectangle的方法,那到底应该调用子类的Foo(Shape)还是应该从父类继承的Foo(Rectangle)方法,这里一点绕点,程序运行结果是调的继承的Foo(Rectangle)方法
第2行 fa调Triangle的方法,子类从写了你类的Triangle的方法,标准的多态

//2 这个为什么都是调子类Foo(Shape) 另一个绕点,为什么这次不调从父类继承的Foo(Rectangle)方法,与上面第一条完全矛盾了啊.

先我们来分清一下这几个情况里的多态和继承关系,多态发生的条件是 重写,继承,要有父类引用指向子类,
那么第一组的第1方法调用没有重写,也不是虚方法,所以不是多态,第2个方法调用是多态
第二组的3个方法调用都不是多态.那没有多态的情况下也应该调我继承的方法啊.

所以这里总结下在这种情况下有一个调用的先后顺序
1.有多态的情况下,肯定是在多态系方法里面去调用,哪些是多态系方法呢? 父类的vitual,子类的override就是多态系方法
2.没有多态的情况下调用自己本生(引用类型,不是this指针)的方法(有的情况下),如果没有再调多态系的方法,自己的方法就是我们的普通方法,new覆盖了的方法,和继承来的方法
3.在 自身方法,与继承方法又有个先后顺序,先自身(或new,new也就是自身覆盖),后继承方法.就算你在写代码是 点出来的方法里有继承的,但是自己方法也会先调用

现在再回来看刚才的几个调用绕点的地方
第一组第1个方法调用,因为不是多态,所以看引用本身,有一个Foo(Rectangle)的方法,所以调父类的(就是他本身的)
第二组第2个方法调用,不是多态,先看引用类型(声明时,不是运行时)本身,Son的Foo(Shape s)方法可以调用,所以不会调用继承来的Foo(Rectangle)
第二组第3个方法调用,不是多态,先看引用类型(声时时,不是运行时)本身,Son的Foo(Shape s)可以调用,所以不会考虑继承(这里没有),也不会考虑多态系里的方法(这里有一个)

对以上的理论纯属个人总结,还没有什么依据,只是大家可以共同多写些例子来测试一下,这个可能同语言解释器有关系,因为Java与C++这一点同C#都是互相不同的,后面我再对比一下Java的不同之处.
我也不是用大量的例子来测试的,所以可能存在不准确的地方,请指正,共同进步.

总结一下:

C#里面 重载,继承的情况下方法的访问顺序

1.类型的本身方法

2.继承方法

3.多态系方法

如果是满足多态的情就简单,表现多态就行了。