我对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
中按预期工作。继承在任何地方的工作方式都相同,所以我哪里出错了。
如果有人可以帮我解决,我将不得不......提前致谢。
答案 0 :(得分:5)
在您的第一个示例中,您实际上并没有覆盖现有方法 - 您正在隐藏它。它是一种特殊的C#机制,与传统的方法覆盖不同。将源方法标记为virtual
并将方法覆盖为override
,以使其按预期工作。 Here's a good explanation。你没有得到关于那个的警告吗?
答案 1 :(得分:3)
默认情况下,Java(IIRC)中的方法为virtual
。在C#中,情况并非如此。
将您的C#方法标记为virtual
和override
。这将产生预期的输出。
答案 2 :(得分:0)
考虑代码
Animal a = new Dog();
a.sound();
为了调用声音方法,运行时需要首先解析实际类型的对象(Dog),然后在其上调用声音方法。如果方法(声音)在类型(Dog)上不存在,则需要在编译时类型(Animal)上调用该方法。
正如您所看到的,此过程可能需要一段时间才能影响性能。为了使这个过程更加高效,C#使用了一个名为"虚拟表"而Java使用一种名为runtime" Dynamic dispatch"的技术。这意味着在C#中,我们需要将方法标记为虚拟,以告诉编译器它需要对基础类型执行查找。这样,与每个对象必须检查需要调用哪个实际方法相比,程序消耗的内存更少,执行速度更快。但是,这也意味着现在需要将每个方法标记为虚拟,以告诉编译器我们需要一个虚拟表来查找该方法。
总之,它是设计哲学的不同之处。 Java使程序员更容易扩展类,而不必担心默认情况下将所有函数都设置为虚拟标记为虚拟的函数。另一方面,当您希望在派生类中重写功能时,C#要求您将功能标记为虚拟。这也有助于消除基类的无意覆盖功能。 (在基类中的C#方法需要在派生类中标记为虚拟和覆盖)