c#学习中关于new和override的一点小结(转载)
最近一周在看C#编程语言,由于以前主要用C语言,在看到new和override两种方法对基类方法不同影响时有点迷糊。花了点时间查了下资料又自己实验了一下,在此小结一下,也算是便于自己记忆吧。
首先,继承不是子类附着到基类上,而是子类先复制基类的成员,再添加上自己的东西形成一个新的整体。
比如按如下定义的两个类:
他们之间的继承关系可以用下图来表示:
class son首先复制parent的两个成员:变量i和方法test(),然后再附加上自己的成员。这时候注意:new关键字定义的test()方法并没有覆盖掉从parent继承过来的方法,而是自己在旁边又新开了一个方法。那么new是怎么来隐藏继承得到的test()方法的呢?
当我们实例化一个对象,son aOfSon = new son(); 这时候aOfSon的类型是son类型,那么son类型的成员列表中有{ j , i , test(), test2()} , 成员指向的对象如图所示:
当调用aOfSon.test()的时候指向的是新建立的new test(),从而隐藏了从基类继承而来的test()。
现在我们转换aOfSon的类型,将其隐式地转换为parent类型 parent aOfPar = aOfSon;
这时候aOfPar是parent类型,parent中只有两个成员变量{ i , test()} ,其指向如下图所示
尽管此时aOfPar在堆中分配的内存中可能还是存在j,new test()和test2(),(此处为猜想,未验证)
但是此时它的类型为parent,不包含对这三个成员的引用,因此无法访问这三个成员。且parent型中的test()成员指向的是老位置上存在的那个旧的test()方法。
上诉的验证代码如下:
//实例化对象
son aOfSon = new son();
parent aOfPar = aOfSon;
//调用函数
Console.WriteLine("Run aOfSon.test()");
aOfSon.test();
Console.WriteLine();
Console.WriteLine("Run aOfPar.test()");
aOfPar.test();
Console.WriteLine();
得到的结果如下:
override与new不同的在于它不是在继承而来的test()旁边新建了一个new test(),而是直接覆盖了继承而来的test()
现将两个类定义如下
它们之间的继承关系如下图所示:
class son首先复制parent的两个成员:变量i和方法test(),然后再附加上自己的成员。这时候注意,class son中的test()方法覆盖了继承而来的test()方法,占领了原先旧方法的位置。
这时候son类型对象的成员指向情况如下图所示:
parent类型对象的成员指向如下图所示
关键在于子类重写的test()方法占据了原本继承而来的test()方法的位置,所以当用parent型对象调用test()方法时,它指向的是新建立的test()方法(实际上它的指向位置没有变)。
那么既然我们已经重写了基类的test()方法,那么为什么在test2()中还能通过base来访问原本的test()方法呢?
这就是因为继承并不是直接在基类上做更改,而是先创建一个基类的副本,然后再此基础上做修改。在test2()中我们又从基类复制了它的test()方法并封装在test2()方法中。
如下图所示
测试代码如下:
//实例化对象
son aOfSon = new son();
parent aOfPar = aOfSon;
//调用函数
Console.WriteLine("Run aOfSon.test()");
aOfSon.test();
Console.WriteLine();
Console.WriteLine("Run aOfPar.test()");
aOfPar.test();
Console.WriteLine();
Console.WriteLine("Run aOfSon.test2()");
aOfSon.test2();
Console.WriteLine();
得到结果如下图:
最后关于virtual和abstract的区别,virtual定义的方法中可以有方法体,且可以被对象直接调用
如上面定义的类,实例化一个基类的对象 parent bOfPar = new parent();
调用它的test()方法
Console.WriteLine("Run bOfPar.test()");
bOfPar.test();
Console.WriteLine();
得到结果如下图
virual定义表示这个方法可以被重写,但不是必须的
abstract只能在抽象类中定义抽象方法,它是空的(没有方法体),在继承它的子类中必须重写该方法