Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
CSharp Language Specification.doc
Скачиваний:
13
Добавлен:
26.09.2019
Размер:
4.75 Mб
Скачать

10.6.2Статические методы и методы экземпляра

Статический метод объявляется с помощью модификатора static. Если модификатор static отсутствует, метод называется методом экземпляра.

Статический метод не выполняет операций с конкретным экземпляром. При использовании зарезервированного слова this в статическом методе возникает ошибка компиляции.

Метод экземпляра выполняет операции с конкретным экземпляром класса, обращение к которому осуществляется с помощью зарезервированного слова this (§7.6.7).

При доступе_к_члену (§7.6.4) с использованием ссылки на метод в форме E.M для статического метода M параметр E должен означать тип, содержащий M, а для метода экземпляра M — экземпляр типа, содержащего M.

Различия между статическими членами и членами экземпляров рассматриваются в разделе §10.3.7.

10.6.3Виртуальные методы

Если объявление метода экземпляра содержит модификатор virtual, метод является виртуальным методом. Если модификатор virtual отсутствует, метод называется невиртуальным методом.

Реализация невиртуального метода инвариантна и одинакова вне зависимости от того, вызывается ли метод для экземпляра класса, в котором он объявлен, или для экземпляра производного класса. В отличие от этого, реализация виртуального метода может быть заменена производными классами. Процесс замены реализации унаследованного виртуального метода называется переопределением этого метода (§10.6.4).

При вызове виртуального метода тип времени выполнения экземпляра, для которого осуществляется вызов, определяет фактическую реализацию вызываемого метода. При вызове невиртуального метода определяющим фактором является тип времени компиляции экземпляра. Говоря точнее, если метод N вызывается со списком аргументов A на экземпляре с типом времени компиляции C и с типом времени компиляции R (где R может быть C или экземпляром класса, производного от C), вызов обрабатывается следующим образом.

  • Сначала к C, N и A применяется разрешение перегрузки для выбора конкретного метода M из набора методов, объявленных и унаследованных классом C. Это описано в §7.6.5.1.

  • Затем, если M является невиртуальным методом, вызывается метод M.

  • В противном случае M является виртуальным методом, и вызывается старшая производная реализация метода M по отношению к R.

Для каждого виртуального метода, объявленного в классе или унаследованного им, существует старшая производная реализация метода по отношению к этому классу. Старшая производная реализация виртуального метода M по отношению к классу R определяется следующим образом.

  • Если R содержит представляющее объявление virtual метода M, это является старшей производной реализацией M.

  • В противном случае, если R содержит объявление override метода M, это является старшей производной реализацией M.

  • В противном случае старшей производной реализацией метода M по отношению к R является старшая производная реализация M по отношению к прямому базовому классу R.

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

using System;

class A { public void F() { Console.WriteLine("A.F"); }

public virtual void G() { Console.WriteLine("A.G"); } }

class B: A { new public void F() { Console.WriteLine("B.F"); }

public override void G() { Console.WriteLine("B.G"); } }

class Test { static void Main() { B b = new B(); A a = b; a.F(); b.F(); a.G(); b.G(); } }

В этом примере класс A представляет невиртуальный метод F и виртуальный метод G. Класс B представляет новый невиртуальный метод F, скрывая тем самым унаследованную функцию F, а также переопределяет унаследованный метод G. Выходом для примера является следующее:

A.F B.F B.G B.G

Обратите внимание, что оператор a.G() вызывает метод B.G, а не A.G. Это связано с тем, что фактически вызываемая реализация метода определяется типом времени выполнения (B), а не типом времени компиляции экземпляра (A).

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

using System;

class A { public virtual void F() { Console.WriteLine("A.F"); } }

class B: A { public override void F() { Console.WriteLine("B.F"); } }

class C: B { new public virtual void F() { Console.WriteLine("C.F"); } }

class D: C { public override void F() { Console.WriteLine("D.F"); } }

class Test { static void Main() { D d = new D(); A a = d; B b = d; C c = d; a.F(); b.F(); c.F(); d.F(); } }

классы C и D содержат два виртуальных метода с одинаковыми подписями, один из которых представлен классом A, а второй — классом C. Метод, представляемый классом C, скрывает метод, наследуемый от A. Таким образом, объявление переопределения в классе D переопределяет метод, представленный классом C. При этом в классе D невозможно переопределить метод, представленный классом A. Далее показан вывод для вышеуказанного примера.

B.F B.F D.F D.F

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]