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#机制,与传统的方法覆盖不同。将源方法标记为virtual
,并将重写方法标记为override
,以使其按预期工作。这里有一个很好的解释。你没收到警告吗?
方法在Java (IIRC)中默认为virtual
。在c#中,情况并非如此。
将c#方法标记为virtual
和override
。这会产生预期的输出。
考虑以下代码
Animal a = new Dog();
a.sound();
为了调用sound方法,运行时需要首先解析对象(Dog)的实际类型,然后在其上调用sound方法。如果在类型(Dog)上不存在方法(sound),则需要在编译时类型(Animal)上调用该方法。
可以看到,这个过程可能需要一段时间,并且会影响性能。为了使这个过程更高效,c#使用了一种叫做"虚拟表"的技术,而Java使用了一种叫做运行时"动态调度"的技术。这意味着在c#中,我们需要将一个方法标记为virtual,以告诉编译器它需要对底层类型执行查找。与每个对象都必须检查需要调用哪个实际方法相比,这种方法消耗的内存少得多,执行速度也快得多。然而,这也意味着现在需要将每个方法标记为virtual,以告诉编译器我们需要一个虚表来查找该方法。
总之,就是设计理念的不同。Java通过将所有函数默认为虚函数,使程序员更容易扩展类,而不必担心将哪些函数标记为虚函数。另一方面,当你想在派生类中重写函数时,c#要求你将函数标记为virtual。这也有助于消除基类的无意重写功能。(在c#中,基类中的方法需要标记为virtual,并在派生类中重写)