C#中继承的奇怪行为

时间:2014-05-05 05:37:06

标签: c# java inheritance implicit-conversion explicit-conversion

我对C#很陌生,所以我希望如果我的问题听起来很愚蠢请原谅我的无知。

- 我正在尝试使用Inheritance C#基础并发现它表现得很奇怪,所以我想用Java来查看它,我得到了我的预期结果。

- 我只是想知道这里有什么我想念的.......

C#CODE:

 class Animal
 {
   public void Sound()
   {
     System.Console.WriteLine("I don't make any sound");
   }


 } 





 class Dog : Animal
 {
   public void Sound()
   {
     System.Console.WriteLine("barking");


   }  

 }


 class InheritTest
 {
   static void Main()
   {
     Animal a = new Dog();         // Implicit conversion

     Dog    d = (Dog) a;   // Explicit conversion


     a.Sound();
     d.Sound();

   }

 }

输出:

I don't make any sound
barking

JAVA代码:

 class Animal
 {
   public void sound()
   {
     System.out.println("I don't make any sound");
   }


 } 





 class Dog extends Animal
 {
   public void sound()
   {
     System.out.println("barking");


   }  

 }


 class InheritTest
 {
   public static void main(String[] args)
   {
     Animal a = new Dog();         // Implicit conversion

     Dog    d = (Dog) a;   // Explicit conversion


     a.sound();
     d.sound();

   }

 }

输出:

barking
barking

- 现在我对这整集的疑问是...... C#我将Dog object分配到{{1}类型的对象引用变量a然后,当我在Animal上调用方法Sound()时,我应该将输出作为a(这是Dog类中的重写方法),而是barking方法被称为输出为Animal's Sound()

- 但在I don't make any sound按预期工作。继承在任何地方的工作方式都相同,所以我哪里出错了。

如果有人可以帮我解决,我将不得不......提前致谢。

3 个答案:

答案 0 :(得分:5)

在您的第一个示例中,您实际上并没有覆盖现有方法 - 您正在隐藏它。它是一种特殊的C#机制,与传统的方法覆盖不同。将源方法标记为virtual并将方法覆盖为override,以使其按预期工作。 Here's a good explanation。你没有得到关于那个的警告吗?

答案 1 :(得分:3)

默认情况下,Java(IIRC)中的方法为virtual。在C#中,情况并非如此。

将您的C#方法标记为virtualoverride。这将产生预期的输出。

答案 2 :(得分:0)

考虑代码

Animal a = new Dog();
a.sound();

为了调用声音方法,运行时需要首先解析实际类型的对象(Dog),然后在其上调用声音方法。如果方法(声音)在类型(Dog)上不存在,则需要在编译时类型(Animal)上调用该方法。

正如您所看到的,此过程可能需要一段时间才能影响性能。为了使这个过程更加高效,C#使用了一个名为"虚拟表"而Java使用一种名为runtime" Dynamic dispatch"的技术。这意味着在C#中,我们需要将方法标记为虚拟,以告诉编译器它需要对基础类型执行查找。这样,与每个对象必须检查需要调用哪个实际方法相比,程序消耗的内存更少,执行速度更快。但是,这也意味着现在需要将每个方法标记为虚拟,以告诉编译器我们需要一个虚拟表来查找该方法。

总之,它是设计哲学的不同之处。 Java使程序员更容易扩展类,而不必担心默认情况下将所有函数都设置为虚拟标记为虚拟的函数。另一方面,当您希望在派生类中重写功能时,C#要求您将功能标记为虚拟。这也有助于消除基类的无意覆盖功能。 (在基类中的C#方法需要在派生类中标记为虚拟和覆盖)