наследование интерфейсов
Сейчас я покажу, как определить тип, реализующий интерфейс, создать экземпляр
этого типа и использовать полученный объект для вызова интерфейсных методов.
В C# это делается очень просто, внутренняя реализация чуть сложнее, но об этом —
немного позже.
336
Глава.13 .Интерфейсы
Интерфейс
System.IComparable
определяется так (в
MSCorLib dll
):
public interface IComparable {
Int32 CompareTo(T other);
}
Следующий код демонстрирует, как определить тип, реализующий этот интер-
фейс, и код, сравнивающий два объекта
Point
:
using System;
// Объект Point является производным от System.Object
// и реализует IComparable в Point
public sealed class Point : IComparable
{
private Int32 m_x, m_y;
public Point(Int32 x, Int32 y) {
m_x = x;
m_y = y;
}
// Этот метод реализует IComparable в Point
public Int32 CompareTo(Point other) {
return Math.Sign(Math.Sqrt(m_x * m_x + m_y * m_y)
- Math.Sqrt(other.m_x * other.m_x + other.m_y * other.m_y));
}
public override String ToString() {
return String.Format("({0}, {1})", m_x, m_y);
}
}
public static class Program {
public static void Main() {
Point[] points = new Point[] {
new Point(3, 3),
new Point(1, 2),
};
// Вызов метода CompareTo интерфейса IComparable объекта Point
if (points[0].CompareTo(points[1]) > 0) {
Point tempPoint = points[0];
points[0] = points[1];
points[1] = tempPoint;
}
Console.WriteLine("Points from closest to (0, 0) to farthest:");
foreach (Point p in points)
Console.WriteLine(p);
}
}
Компилятор C# требует, чтобы метод, реализующий интерфейс, отмечался
модификатором
public
. CLR требует, чтобы интерфейсные методы были виртуаль-
337
Наследование.интерфейсов
ными. Если метод явно не определен в коде как виртуальный, компилятор сделает
его таковым и, вдобавок, запечатанным. Это не позволяет производному классу
переопределять интерфейсные методы. Если явно задать метод как виртуальный,
компилятор сделает его таковым и оставит незапечатанным, что предоставит про-
изводному классу возможность переопределять интерфейсные методы.
Производный класс не в состоянии переопределять интерфейсные методы,
объявленные запечатанными, но может повторно унаследовать тот же интерфейс
и предоставить собственную реализацию его методов. При вызове интерфейсного
метода объекта вызывается реализация, связанная с типом самого объекта. Сле-
дующий пример демонстрирует это:
using System;
public static class Program {
public static void Main() {
/************************* Первый пример *************************/
Base b = new Base();
// Вызов реализации Dispose в типе b: "Dispose класса Base"
b.Dispose();
// Вызов реализации Dispose в типе объекта b: "Dispose класса Base"
((IDisposable)b).Dispose();
/************************* Второй пример ************************/
Derived d = new Derived();
// Вызов реализации Dispose в типе d: "Dispose класса Derived"
d.Dispose();
// Вызов реализации Dispose в типе объекта d: "Dispose класса Derived"
((IDisposable)d).Dispose();
/************************* Третий пример *************************/
b = new Derived();
// Вызов реализации Dispose в типе b: "Dispose класса Base"
b.Dispose();
// Вызов реализации Dispose в типе объекта b: "Dispose класса Derived"
((IDisposable)b).Dispose();
}
}
// Этот класс является производным от Object и реализует IDisposable
internal class Base : IDisposable {
// Этот метод неявно запечатан и его нельзя переопределить
public void Dispose() {
Console.WriteLine("Base's Dispose");
}
}
продолжение
338
Do'stlaringiz bilan baham: |