Странное поведение с наследованием в C#
Я довольно новичок в C#, поэтому я надеюсь, что если мой вопрос звучит глупо, прошу прощения за мое невежество.
- Я пытался Inheritance
фундамент с C#
и обнаружил, что он ведет себя странным образом, поэтому я решил проверить Java
и я получил ожидаемый результат.
- Я просто хочу знать, есть ли что-то, что я здесь скучаю.......
C# КОД:
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
в переменную ссылки на объект a
типа Animal
тогда, когда я вызываю метод Sound()
на a
я должен получить вывод как barking
(который является переопределенным методом в классе Dog), но вместо Animal's Sound()
метод называется давая вывод как I don't make any sound
,
- Но в Java
все работает, как и ожидалось.. Наследование работает одинаково везде, так где я ошибся.
Я буду признателен, если кто-то может помочь мне с этим...... Заранее спасибо.
3 ответа
В первом примере вы на самом деле не переопределяете существующий метод - вы его скрываете. Это специальный механизм C#, который отличается от переопределения традиционного метода. Отметить метод источника как virtual
и переопределить метод как override
чтобы это работало так, как вы ожидаете. Вот хорошее объяснение. Разве вы не получили предупреждение об этом?
Методы virtual
по умолчанию в Java (IIRC). В C# это не так.
Отметьте ваши методы C# как virtual
а также override
их. Это даст ожидаемый результат.
Рассмотрим код
Animal a = new Dog();
a.sound();
Чтобы вызвать метод звука, среда выполнения должна сначала разрешить фактический тип объекта (Dog), а затем вызвать метод звука для него. Если метод (sound) не существует для типа (Dog), необходимо вызвать метод для типа времени компиляции (Animal).
Как видите, этот процесс может занять некоторое время и повлиять на производительность. Чтобы сделать этот процесс более эффективным, C# использует нечто, называемое "виртуальными таблицами", в то время как Java использует технику, называемую динамической диспетчеризацией во время выполнения. Это означает, что в C# нам нужно пометить метод как виртуальный, чтобы сообщить компилятору, что ему нужно выполнить поиск базового типа. Таким образом, программа потребляет намного меньше памяти и работает быстрее, чем если бы каждый объект должен был проверить, какой фактический метод должен быть вызван. Однако это также означает, что теперь каждый метод должен быть помечен как виртуальный, чтобы сообщить компилятору, что нам нужна виртуальная таблица для поиска метода.
Таким образом, это разница в философии дизайна. Java облегчает программистам расширение класса, не беспокоясь о том, какие функции пометить как виртуальные, сделав все функции виртуальными по умолчанию. С другой стороны, C# требует, чтобы вы отмечали функцию как виртуальную, когда вы хотите, чтобы функциональность была переопределена в производном классе. Это также помогает устранить непреднамеренно переопределяющую функциональность базовых классов. (В C# методы в базовом классе должны быть помечены как виртуальные и переопределены в производных классах)