class Program
    {
        static void Main(string[] args)
        {
            B obj = new B();
            obj.PrintFields();
           
        }
    } 
     class A
     {
          public A()
           {
                PrintFields();
           }
          public virtual void PrintFields(){}
      }
    class B : A
    {
        int x = 1;
        int y;
        public B()
        {
            y = -1;
        }
        public override void PrintFields()
        {
            Console.WriteLine("x={0},y={1}", x, y);
        }
    }
}这个程序的执行结果是 X=1,Y=0;x= 1 y = -1有个关键的地方,就是类A中构造函数调用的方法PrintFields()为什么是子类的?不是那个自己的virtral方法?
我觉得它应该调自己的virtual PrintFields()方法,怎么会调子类的重写方法?
请详细解释

解决方案 »

  1.   

    这就是oo中的多态性啊,override修饰符重写了父类的方法,所以obj对象的真实类型是B,就会调用B中的方法。如果用new的话就会调用自己的那个virtual方法,注意一下override和new的区别:
    如果派生类中的方法前面带有 new 关键字,则该方法被定义为独立于基类中的方法。
    如果派生类中的方法前面带有 override 关键字,则派生类的对象将调用该方法,而不是调用基类方法。
      

  2.   

    因为PrintFields()被子类重写了,面向对象的基本概念,楼主要多看看书
      

  3.   

    子类重写的调用自己的是对的,
    我不明白的是加重字体的下面这段
    public A()
              {
                  PrintFields();
              } 这是类A的构造函数,调用的理应是类A的virtual方法,
    但实际他调用的是子类B的方法
    不理解
      

  4.   

    程序的执行应该是下面的流程类A的构造函数A()
    类B的构造函数B()
    类B中的方法PrintFields()难道声明了B的对象,连A的构造函数的对象都是B,所以
    才能调用B的方法PrintFields(),我晕了
      

  5.   

    程序的执行应该是下面的流程类A的构造函数A()
    类B的构造函数B()
    类B中的方法PrintFields()难道声明了B的对象,连A的构造函数的对象都是B,所以
    才能调用B的方法PrintFields(),我晕了
      

  6.   

    代码运行到:public A() 

        PrintFields(); 

    由于类A的PrintFields是虚方法,所以在实际调用方法PrintFields前,会先判断A的子类有没有重写(override)
    这个方法,如果有的话就调用子类的方法,没有,才决定调用的是类A的PrintFields方法楼主可以尝试将B的override去掉,这样调用的就是类A的PrintFields方法了
      

  7.   

    我觉得这里边还有一个对象的问题,
    这是声明的B的对象调用的是这个结果
    如果声明A的对象,
    调用的就是类A 的virtual 方法好像明白点了,又好像晕晕的
      

  8.   

    new貌似就是在托管堆上根据指定的类型创建了一个存储空间可以把它看成一块地。B obj = new B(); 这个时候,相当于根据B的大小以及其父类的大小,在这块地上画一块范围,也就是B+A的面积而代码public A() 

        PrintFields(); 
    } 将其更改为:public A() 

        this.PrintFields(); 
    } 调试的时候会发觉,this的类型是B,所以调用这个PrintFields方法的时候,就有两个选择,用A的或者用B的,之所以会有两个选择,是因为A的PrintFields方法是虚的,同时B也实现了这个方法,由于当初画地的时候,连A带B一起画了,所以才会有两个选择,所以假设B有子类C,而C也override了PrintFields方法,那么在代码运行到构造函数的时候将有3个选择而选择优先使用B的override的PrintFields方法,所以这里将调用B的PrintFields方法。而代码obj.PrintFields(); 由于Obj的类型是B,所以调用的肯定是B的PrintFields如果main将代码变成A obj = new B(); 
    obj.PrintFields(); 结果将会和上面一样。
      

  9.   

    那个如果B继承A,C继承B
    只有new C()的时候,在A的构造函数中调用PrintFields 才会有三种选择
    否则仅仅new B()的话,还是只有两种选择的为什么不能修改自己的回复呢?=。=
      

  10.   

    class Program
        {
            static void Main(string[] args)
            {
                B obj = new B();
                obj.PrintFields();
             
            }
        }
        class A
        {
              public A()
              {
                  PrintFields();
              }
              public virtual void PrintFields(){}
          }
        class B : A
        {
            int x = 1;
            int y;
            public B()
            {
                y = -1;
            }
            public override void PrintFields()
            {
                Console.WriteLine("x={0},y={1}", x, y);
            }
        }

    是类初始化顺序你没有高明白了
    先是基类的构造函数,然后是继承类的构造函数
    这里先是a的构造函数,调用PrintFields();,但是a的PrintFields();是虚拟的,什么都没有做,然后调用他的实现方法,就是b的PrintFields();,显示x,y,这时候x是初始化为1,y没有初始化,默认0,所以显示x=1,y=0。
    然后构造b,调用b的构造函数,把y初始化为-1.然后是 obj.PrintFields();这句,调用了b的PrintFields()方法,显示x和y,这是后x没有变,y在b的构造函数中赋值-1
    所以显示的时候就是x=1,y=-1
    执行结果是 X=1,Y=0;x= 1 y = -1 
      

  11.   

    你明明在main函数里声明的是B对象而不是A的对象,为什么要调用A的方法?你声明个A对象试试?