Почему мы назначаем объект дочернего класса исходной переменной родительского класса?
У меня есть следующий код.
public class Parent
{
public void Print()
{
Console.WriteLine ("Parent Method");
}
}
public class Child : Parent
{
public new void Print()
{
Console.WriteLine ("Child Method");
}
}
public class Program
{
public static void Main()
{
Child C = new Child();
C.Print();
}
}
Если я запустил этот код, я получаю результат "Child Method"
Но если я сделаю следующее, почему я получаю результат "Родительский метод"?
public class Parent
{
public void Print()
{
Console.WriteLine ("Parent Method");
}
}
public class Child : Parent
{
public new void Print()
{
Console.WriteLine ("Child Method");
}
}
public class Program
{
public static void Main()
{
Parent P = new Child(); // The only difference is this.
P.Print();
}
}
Единственное отличие:
Child C = new Child();
Parent P = new Child();
Я думал, что new Child()
означает, что мы создаем экземпляр класса Child
.
И я думал, что оба, C
и P
, являются просто объектными ссылочными переменными, которые содержат расположение экземпляра класса Child
.
Можете ли вы исправить меня, если я ошибаюсь или скажу, если я пропущу что-то, потому что я не понимаю, почему в вышеуказанных случаях я получаю разные результаты?
Ответы
Ответ 1
Это потому, что вы обновили метод Print
в Child
. Поэтому во время компиляции P.Print()
разрешается Parent.Print
, но C.Print()
разрешается Child.Print()
. Если у вас был виртуальный метод, который был переопределен в Child
вместо этого, они оба напечатали "Child Method":
public class Parent
{
// Declare this as virtual, allowing it to be overridden in
// derived classes. The implementation will depend on the
// execution-time type of the object it called on.
public virtual void Print()
{
Console.WriteLine ("Parent Method");
}
}
public class Child : Parent
{
// Override Parent.Print, so if Print is called on a reference
// with compile-time type of Parent, but at execution it
// refers to a Child, this implementation will be executed.
public override void Print()
{
Console.WriteLine ("Child Method");
}
}
по теме:
Ответ 2
Вот что происходит под капотом
Child C = new Child();
C.Print();
Потому что вы скрываете методы, а не переопределяете их. поэтому метод Print в Parent скрыт и вызывается функция Child.Print().
![введите описание изображения здесь]()
Parent P = new Child(); // The only difference is this.
P.Print();
Это (New Child()) будет вызываться в справочнике типа родителя.
![введите описание изображения здесь]()
если вы попробуете это, ссылка типа родителя будет выбрана для типа Child. Отныне вызывается Child.Print().
Parent P = new Child();
((Child)P).Print();
![введите описание изображения здесь]()
вывод будет: Детский метод
Ответ 3
Поскольку метод Print
не является virtual
, компилятор не будет генерировать код, чтобы сообщить CLR, чтобы вызвать метод в соответствии с фактическим типом времени выполнения.
Итак, когда ваша переменная называется Child
, будет вызвана Child.Print
. Но, когда вы обращаетесь к нему как Parent
, Parent.Print
будет использоваться.
Использование ключевого слова new
предназначено только для теневого копирования, чтобы сообщить компилятору, что дочерний метод действительно скрывает родительский метод и не отменяет его, но не имеет никакого эффекта.
Ответ 4
JCronin, вы отправляете родителя с родителем P = new Child(). Чтобы получить поведение класса Child, вам нужно либо вернуть его обратно ребенку (var x = (Child) P), либо создать экземпляр экземпляра Child (Child P = new Child()).
См. Downcasting
Ответ 5
Потому что вы объявили тип P
Parent
. Когда вы назначаете ему Child
, он будет передан этому типу.