首相A的G是个虚方法,而在派生类B中重写了它
A a=b;是用A的引用a去引用B的实例b,所以实际
调用的是B的G方法!

解决方案 »

  1.   

    那a.F()方法输出的为什么是A.F
      

  2.   

    那a.F()方法输出的为什么是A.F因为F不是虚方法
    虚方法我知道,关键是不知道编译时附值与运行是附值具体的内部操作差别再哪?那个不叫附值,叫引用,而且你必须要理解虚表这个概念
    建议你看看C++对虚函数的解释那样会好些,这一点C#和C++是一致的!
      

  3.   

    我的意思是说既然a引用的是B那么a.F()输出的为什么不是B.F
      

  4.   

    我说的a引用b是通过虚表里的虚函数指针找到b的G
    因为G被改写了,而F不是虚函数,虚表里也没有
    所以找不到!就还是a.F()
      

  5.   

    <<C++编程思想>>有一章讲的很详细!
      

  6.   

    a.F()方法输出的为什么是A.F
    是因为:
    派生类B的f()方法并没有覆盖A中的f()方法,而是导致它隐藏了
      

  7.   

    其实 yarshray(saga jion) 讲的还是比较正确的。不愧是二星级的。
    我只是补充点罢了。这里所牵涉到是类继承中的隐藏和重写两个概念。
    源码中的语法很正确,无可挑剔。
    A.F()没有声明为虚方法,只能被子类隐藏,而不能被重写。
    而A.G()声明为虚方法,可以被重写。B.F()由于声明了 new ,所以 B.F() 将隐藏虚方法 A.F()。隐藏意味着 B 的实例调用 F() 时,将使用 B 中声明的 F() ,而不会与 A.F() 产生岐义。但隐藏并不表明 A.F()被重写,此时即使在同一个 B 类型的实例中 A.F() 与 B.F()是两个不同的方法。所以类型为 A 的实例在调用 F() 时仍然是 A 中原来定义的 F(),尽管所引用的对象是 B 类型。B.G()由于声明了 override ,所以 B.G() 将重写虚方法 A.G()。重写意味着 A.G() 将在创建子类 B 的实例时被 B.G() 覆盖,此时在一个 B 类型的实例中, A.G() 与 B.G()是指同一个方法,即 B.G()。当类型 A 的实例引用的对象是 B 类型的实例时,其实调用的仍旧是 A.G(),但由于 A.G() 被 B.G() 重写(覆盖),所以在实际运行时将使用子类 B 中定义的 G()。然而,在以下代码中:
             A a = new A();
             a.G();
    a.G()调用的是仍旧是 A 中定义的 G()。因为此时实例 a 引用的对象是 A 类型,无法获取重写版本的 G()。也就是说,此时 A.G() 并没有被重写(覆盖)。你也可以试一下这样的代码:
          class B:A
          {
              new public void F(){ Console.WriteLine("B.F") };
              new public void G(){ Console.WriteLine("B.G");}
          }
    使用同样的例程调试一下,对比一下结果,你会有所感悟的。OO 的多态性是很复杂的问题,C# 已经作了许多优化(相对于 C++),还是比较好掌握的。
      

  8.   

    更正:     B.F()由于声明了 new ,所以 B.F() 将隐藏虚方法 A.F()。应改为:
         B.F()由于声明了 new ,所以 B.F() 将隐藏基类中的非虚方法 A.F()。当然方法的签名必须相同。否则是重载,而不是隐藏重写。重载是语法关键词 override 。隐藏是 hide ,用于解释 override 的行为。
      

  9.   

    再一次更正,真不好意思。
    我自己都越解释越糊涂了。Change :
    重载是语法关键词 override 。隐藏是 hide ,用于解释 override 的行为。TO :
    重写是语法关键词 override,有时也称为覆盖。隐藏是 hide ,用于解释 new 的行为。