@Jypsy

Как сработает переопределение?

Объясните пожалуйста, почему в консоль выводится А.
Ведь если я все правильно понимаю, в данной строчке A ac = new C(); вызывается те методы, что есть у класса А (так как это тип переменной), но реализация их будет вызвана из С, то есть выведет С.

using System;
using System.Collections.Generic;
using System.IO;
namespace ProjectOne {
	public abstract class A{
		public virtual string Print(){
			return "A";
		}
	}
	public class B:A{
		public virtual new string Print(){
			return "B";
		}
	}
	public class C:B{
		public override string Print(){
			return "C";
		}
	}
	class EntryPoint {
		static void Main(string [] args){
		A ac = new C();
		Console.WriteLine (ac.Print());
		}

	}}
  • Вопрос задан
  • 189 просмотров
Решения вопроса 1
lexxpavlov
@lexxpavlov
Программист, преподаватель
В классе A метод Print отмечен виртуальным, то есть, его можно переопределить. Но в наследнике B нет переопределения этого метода, а создаётся новый виртуальный метод с тем же именем - ключевое слово new указывает, что создаётся новый метод, не связанный с методом A.Print.
В классе C метод Print переопределяет метод родителя, то есть, метод B.Print, но не переопределяет метод A.Print.
Так как у переменной указан тип A, то вызов ac.Print() вызовется метод - единственный из реализаций метода A.Print.

Вот смотрите, чтобы было понятнее:
class A { public virtual void Print() { Console.WriteLine("A"); } }
class B : A { public override void Print() { Console.WriteLine("B"); } }
class C : B { public new virtual void Print() { Console.WriteLine("C"); } }
class D : C { public override void Print() { Console.WriteLine("D"); } }

A ad = new D();
ad.Print(); // покажет B
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
@Free_ze
Пишу комментарии в комментарии, а не в ответы
Метод помечен виртуальным (virtual), поэтому компилятор подставляет код виртуального вызова метода (IL-инструкция callvirt), а не непосредственного (call). В дотнете у каждого объекта есть неявная ссылка на его соответствующий (реальный) объект-тип. Через эту ссылку находится адрес правильного метода.

В других языках все может быть устроено иначе. А об устройстве дотнета более подробно вы можете почитать в книжке Джеффри Рихтера "CLR via C#...".
Ответ написан
Комментировать
@OREZ
virtual new "прерывает" цепочку переопределения метода, поэтому для базового типа будет вызван самый последний в цепочке из переопределенных до первого "прерванного"
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы