2015-06-22 3 views
1

Предположим, что у меня есть родительский класс и дочерний класс, и я перегрузил один из методов родительского класса.Метод вызова в наследовании

Я назначаю объект класса child ссылочной переменной PARENT CLASS. Я знаю, что, когда я пытаюсь вызвать метод родительского класса, он вызовет метод класса child.

Но в чем причина этого? что такое программный поток управления? И что происходит внутри кучи?

+0

[Вот блог от Эрика Липперта об этом.] (Http://blogs.msdn.com/b/ericlippert/archive/2011/03/17/implementing-the-virtual-method-pattern-in- c-part-one.aspx) –

ответ

5

«Магия» - это справочная таблица.

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

Таким образом, вместо компиляции при вызове определенного метода по определенному адресу вызов будет скомпилирован как поиск, а затем вызов значения, которое было извлечено из таблицы.

Например, предположим, что базовый тип имеет эту таблицу:

[1000] 

Для первого типа, рассматриваемый метод является по адресу 1000.

Для второго типа, эта таблица выглядит это:

[2000] 

То же самое (переопределены) метод в настоящее время по адресу 2000.

Если метод не был виртуальным, вызов к нему, как этот вызов:

baseObject.Method1(); 

будет составлен на что-то вроде этого:

call method at address 1000 

Но теперь вместо этого он будет выглядеть примерно так:

get address to type virtual method table (vtable) 
get adress from index 0 in the table 
call the method at that address 
+0

Не могли бы вы объяснить, пожалуйста, подробно –

+1

Добавлена ​​дополнительная информация. –

1

Есть два ключевых фактора, которые делают возможным dynamic dispatch:

  1. Каждый объект определенного типа имеет указатель на , который содержит (указатели на) реализации виртуального метода, которые действительны для , что и тип.
  2. Inheritance не меняет порядок методов в таблице (он может просто добавить больше методов в конце), поэтому метод сохраняет тот же индекс, что и вы переопределяете его в дочерних классах (и создаете больше таблиц).

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

  • Из-за (1) выше, в зависимости от того типа объекта, случается, есть во время выполнения (в отличие от типа, объявленного во время компиляции), будет использована таблица поиска, содержащая правильные реализации методы.
  • И из-за вышеприведенного (2) индекс, используемый компилятором, «найдет» правильный метод, хотя тип времени выполнения (и, следовательно, таблица поиска) неизвестен во время компиляции.

Фактически, механизм работает для типов, которых еще нет! Вызов метода может быть записан и скомпилирован задолго до того, как кто-то сделает специфические для него типы дочерних типов и методов.

Отказ от ответственности: фактические сведения о реализации C# более сложны, чем описано выше (например, интерфейсы требуют двойного поиска, есть отражение и т. Д.), Но основная идея остается прежней.

Смежные вопросы