c#中继承的奇怪行为

本文关键字:继承 | 更新日期: 2023-09-27 18:01:45

我是c#的新手,所以我希望如果我的问题听起来很傻,请原谅我的无知。

-我正在用C#尝试Inheritance funda,发现它以某种奇怪的方式表现,所以我想用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 CODE:
 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分配到类型为Animal的对象引用变量a中,然后当我在a上调用方法Sound()时,我应该将输出作为barking(这是在狗类中被覆盖的方法),而是将Animal's Sound()方法称为输出作为I don't make any sound

-但是在Java中,按预期工作。继承在任何地方都以同样的方式工作,所以我哪里出错了。

如果有人能帮我解决这个问题......我将不胜感激

c#中继承的奇怪行为

在您的第一个示例中,您实际上并没有重写现有方法-您隐藏了它。它是一种特殊的c#机制,与传统的方法覆盖不同。将源方法标记为virtual,并将重写方法标记为override,以使其按预期工作。这里有一个很好的解释。你没收到警告吗?

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

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

考虑以下代码

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

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

可以看到,这个过程可能需要一段时间,并且会影响性能。为了使这个过程更高效,c#使用了一种叫做"虚拟表"的技术,而Java使用了一种叫做运行时"动态调度"的技术。这意味着在c#中,我们需要将一个方法标记为virtual,以告诉编译器它需要对底层类型执行查找。与每个对象都必须检查需要调用哪个实际方法相比,这种方法消耗的内存少得多,执行速度也快得多。然而,这也意味着现在需要将每个方法标记为virtual,以告诉编译器我们需要一个虚表来查找该方法。

总之,就是设计理念的不同。Java通过将所有函数默认为虚函数,使程序员更容易扩展类,而不必担心将哪些函数标记为虚函数。另一方面,当你想在派生类中重写函数时,c#要求你将函数标记为virtual。这也有助于消除基类的无意重写功能。(在c#中,基类中的方法需要标记为virtual,并在派生类中重写)