Присвоение производного объекта класса родительской ссылке на класс - PullRequest
5 голосов
/ 05 декабря 2011

Я всегда удивляюсь, когда вижу:

Parent ref = new Child();

, где дочерний класс расширяет Parent.

  1. Как выглядит объект ref в памяти?
  2. Как лечится виртуальный метод? невиртуальном
  3. Чем он отличается от:
Child ref = new Child();

Ответы [ 4 ]

6 голосов
/ 06 декабря 2011

Как выглядит объект в памяти?

Ваш вопрос неясен.Есть две соответствующие ячейки памяти.Переменная связана с местом хранения.Это место хранения содержит ссылку на другое место хранения.

Место хранения переменной обычно реализуется как четырех- или восьмибайтовое целое число, которое содержит «управляемый указатель» - адрес памяти, известный сборщику мусора.

Структура памяти объекта также является деталью реализации CLR.Буфер памяти, связанный с объектом, будет содержать все данные для объекта - все значения полей и еще много чего.Он также содержит ссылку на еще одну другую область памяти, таблицу виртуальных функций объекта.

Таблица виртуальных функций (vtable) затем содержит еще больше ссылок , на этот раз ссылки, которые относятся к методам, связанным с наиболее производным типом объекта.

Как лечится виртуальный метод?невиртуальном?

Виртуальные методы выполняются путем поиска ссылки на объект из переменной, затем поиска в vtable, затем поиска метода в vtable и вызова этого метода.

Не виртуальные методы не вызываются через vtable, потому что они известны во время компиляции.

Чем он отличается от ...

Не виртуальные методы, вызываемыеобъект будет вызывать версию метода, основанную на типе переменной .Виртуальные методы, вызываемые для объекта, будут вызывать версию метода, основанную на типе объекта , на который ссылается переменная.

Если это не все ясно, возможно, вы захотите прочитатьмоя статья, в которой объясняется, как можно «эмулировать» виртуальные методы на языке, в котором их нет.Если вы сможете понять, как самостоятельно реализовать виртуальные методы на языке, в котором их нет, это поможет вам понять, как мы на самом деле делаем реализуем виртуальные методы.

http://blogs.msdn.com/b/ericlippert/archive/2011/03/17/implementing-the-virtual-method-pattern-in-c-part-one.aspx

2 голосов
/ 05 декабря 2011

ref является Child объектом. виртуальные методы вызываются в Child классе. Однако методы, определенные только в классе Child, не отображаются при назначении объекту Parent.

Если foo() не было виртуальным, то компиляция выберет метод на основе объявленного типа переменной ref. Если у вас есть Parent ref = new Child();, то будет вызван Parent.foo(). Если у вас есть Child ref = new Child();, то будет звонить Child.foo(). Конечно, в этом случае компилятор C # попросит вас использовать new в объявлении Child.foo(), чтобы указать, что вы хотите скрыть реализацию в Parent.

0 голосов
/ 06 декабря 2011

Подумайте об этом так (при условии, что Parent не является абстрактным классом)

Parent ref = new Child();

и

Parent ref = new Parent();

В основном те же самые, за исключением виртуальных методов, переопределенных в Child, будут вызываться в первом, но не во втором.

Тип , который вы объявляете как объект, будет определять, какие методы доступны для него. Объявление объекта менее конкретным типом, чем тот, для которого вы его создаете - в первом случае - может влиять на то, какие методы вызываются в время выполнения , но только если эти методы объявлены как абстрактные или виртуальный.

В любом случае представьте, что вы вызвали метод foo в работе. Среда выполнения будет штрафовать метод foo в классе Parent. Затем среда выполнения увидит, является ли foo виртуальным (или абстрактным). Если бы foo не было виртуальным или абстрактным, среда выполнения вызывала бы определение foo Parent прямо там и тогда, и с этим покончено. Однако, если бы foo были виртуальными или абстрактными, среда выполнения проверила бы, действительно ли ref действительно создан для более специфического типа, который перекрывает foo. Если это так, он будет называть , что foo

0 голосов
/ 06 декабря 2011

Я думаю, ref просто содержит адрес, по которому может быть найден упомянутый объект Child. Если вы вызываете виртуальный метод, фактический вызванный метод зависит от динамического типа объекта (Child); если вы вызываете не виртуальный метод, это зависит от статического типа (Parent). Это отличается от Child ref = ..., потому что в этом статический тип Child, а не Parent.

И я надеюсь, что это не домашнее задание:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...