Это на самом деле не перекрывает, это затеняет это. При наличии ссылки на объект Derived
функция Base
HelpMeNow
не будет доступна 1 , а derivedObject.HelpMeNow()
вызовет реализацию Derived
.
Это не то же самое, что переопределение виртуальной функции, которой не является HelpMeNow
. Если объект Derived
хранится в ссылке на Base
или на IHelper
, то будет вызываться Base
*1016*, и реализация Derived
будет недоступна.
Derived derivedReference = new Derived();
Base baseReference = derivedReference;
IHelper helperReference = derivedReference;
derivedReference.HelpMeNow(); // outputs "Derived.HelpMeNow()"
baseReference.HelpMeNow(); // outputs "Base.HelpMeNow()"
helperReference.HelpMeNow(); // outputs "Base.HelpMeNow()"
Конечно, если вышеупомянутое не является желаемым поведением, и обычно это не так, есть две возможности. Если вы управляете Base
, просто измените HelpMeNow()
на виртуальный и переопределите его в Derived
вместо его теневого копирования. Если вы не контролируете Base
, то вы можете, по крайней мере, исправить это на полпути, переопределив IHelper
, вот так:
class Derived : Base, IHelper{
public new void HelpMeNow(){Console.WriteLine("Derived.HelpMeNow()");}
void IHelper.HelpMeNow(){HelpMeNow();}
}
Эта версия Derived
использует так называемую явную реализацию интерфейса , которая позволяет вам выполнить контракт на реализацию интерфейса без добавления реализации к общедоступному интерфейсу вашего класса. В этом примере у нас уже есть реализация в открытом интерфейсе Derived
, которая унаследована от Base
, поэтому мы должны явно реализовать IHelper
, чтобы изменить ее 2 . В этом примере мы просто перенаправляем реализацию IHelper.HelpMeNow
на наш открытый интерфейс, который является тенью Base
.
Таким образом, с этим изменением вызов baseReference.HelpMeNow()
по-прежнему выводит "Base.HelpMeNow ()", но вызов helperReference.HelpMeNow()
теперь будет выводить "Derived.HelpMeNow ()". Не так хорошо, как изменение реализации Base
на виртуальную, но так же хорошо, как мы получим, если не будем контролировать Base
.
1 Исключение: он является доступным из методов Derived
, но только при наличии base.
, как в base.HelpMeNow()
.
2 Обратите внимание, что мы также должны объявить IHelper
как интерфейс, который реализует класс, даже если мы наследуем это объявление от Base
.