关于类的继承的一个例子

学习面向对象,继承是一个不得不说的问题。从C++开始,我们就学习继承和接口。呵呵,昨天收到一间叫网龙公司的面试Email,先发个试题来做的Email面试还是第一次见识。可能偶面试经验少吧(不超过十次),面试题目里面有一个问题很适合用来作为继承的讲解例子。

因为这个例子实在太美妙了,忍不住做了一下,并试着分析了。问题如下:

问下面代码的输出结果:

     public class A
     
{
         
public virtual void print1(int i)
         
{
             Console.WriteLine(i);
         }


         
public void print2(A a)
         
{
             a.print1(
1);
             print1(
5);
         }

     }


     
public class B : A
     
{
         
public override void print1(int i)
         
{
             
base.print1(i+1);
         }

     }


     
public static void Main()
     
{
         B b 
= new B();
         A a 
= new A();

         a.print2(b);
         b.print2(a);
         a.print2(a);
         b.print2(b);
     }


实际输出结果是2、5、1、6、1、5、2、6

我们来分析一下:

  在代码中a.print2(b),输出结果是2、5。因为a.print2(b)实际上参数是A a = new B()形式初始化的,所以执行a.print1(1)的时候实际是执行B类的print1,因为用B类初始化,而B类重写了print1嘛。所以就是实际是b.print1(i),也就是执行base.print(i+1),所以结果是2。当执行print1(5)的时候,这时候与参数无关,只与a.print2(b)中的a.有关,即是显式执行a.print1(5),当然输出结果就是5了。

   在b.print2(a)中,输出结果是1、6。因为b.print1(a)实际上参数初始化是A a =  new A(),因为b中根本没有print2函数,所以执行父类A中的print2函数。print2函数中a.print1(1),因为用A声明而且用A初始化,所以执行a.print1(1),显式执行父类print1,所以结果是1。当执行print1(5)的时候,与初始化的参数无关,只与b.print2(a)中的b.有关,即是执行b.print1(5),因为b.print1是重写过的,所以执行结果是6。

   在a.print2(a)中输出1,5。 参数初始化A a = new A() 所以执行a.print1(1),a.print1(5)。这个比较简单。

   在b.print2(b)中输出2,6。 参数初始化A a = new B() 所以执行b.print1(1),b.print1(5)。这个也正路,没有特别的地方。

BTW,记下一些关于继承的知识点:

1、Object类是所有类的基类。

2、构造函数和析构函数不能被继承,但会被子类初始化的时候调用。

3、子类继承父类除构造函数和析构函数以外的一切成员,不论父类对它们定义了什么样的访问方式,都能被继承,访问方式只能限定子类是否能访问它们。

4、子类可以通过定义和父类同名的成员来覆盖父类成员,但是并没有删除父类的成员,只是屏蔽了不能访问。

5、可以通过定义虚方法,虚属性,虚索引等来让子类重载达到多态的目的。

6、C#中的类只能单重继承,不能实现多重继承。但是接口可以多重继承。

7、类的声明和初始化就像一个模具和用料的关系,声明是模具,初始化是将材料放入模具使之成形。例如父类A定义一个虚方法function1(),一个方法function2(),子类B继承父类A,并覆写function1()和重写function2(),如下声明初始化:

A a = new B();

因为是用父类A声明,用子类B初始化,所以当调用a.function1()的时候,调用的是子类覆写的function1(),但当用a.function2()的时候,因为子类只重写了function2而不是覆写,而类的声明是用父类A声明的,就像已经使用了A的模具,但是用的料是模具B的料。无论料是什么,出来的形状始终是A的形状,所以,a.function2()会调用父类的function2()方法。(A类的function1()声明是虚方法,就是说该模具的function1()部分是可以改变的,可以当子类初始化的时候可以看成是子类B改变了A模具的function1()的形状,所以a.function1()出来的是B的形状,就是调用B的function1()方法。)。这个比喻有点勉强,但是能说明类继承之间的关系。

8、在声明类和初始化中,不能用子类声明但用父类初始化(好像这个是当然的,汗~)也就是说,“=”号右边的类总是左边的派生类(当然自身也OK)。

9、还没有想到,想到再写~~呵呵!

 

posted @ 2006-08-29 15:34  KenBlove  阅读(747)  评论(0编辑  收藏  举报