Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Podbelsky_V_V_C_Bazovy_kurs.pdf
Скачиваний:
69
Добавлен:
02.06.2015
Размер:
1.73 Mб
Скачать

312

Г л а в а 1 5

 

 

доступа к объектам разных типов невозможно – у каждого типа своя структура, свои члены, свои поля. В теле цикла условные операторы, предназначенные для распознавания типов. Распознаются только типы double и PointS. В качестве проверяемого условия в операторах if используется выражение с операцией is. Обратите внимание на то, как с помощью выражения с индексацией выполнено присваивание второму элементу массивасписка:

dinamo[1] = 1.23;

Перед этим присваиванием значением элемента dinamo[1] был объект структуры PointS.

15.5. Реализация структурами интерфейсов

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

Такой возможности для объектов разнотипных структур нет, так как структуры не наследуются. Однако структуры могут реализовывать интерфейсы. Если несколько структурных типов реализуют один и тот же интерфейс, то к объектам этих разных структур применимы методы (а также свойства, индексаторы и события) интерфейса. Тем самым интерфейсы позволяют одинаково обрабатывать объекты разных структурных типов. Для этого ссылка на интерфейс используется в качестве параметра, вместо которого могут подставляться аргументы структурных типов, реализующих данный интерфейс. Второй пример – применение коллекций (частный случай – массивов), элементы которых имеют разные структурные типы. Создание такого массива возможно, если он объявлен с типом интерфейса, реализованного всеми структурными типами.

В качестве примера определим интерфейс с прототипами свойств:

interface IShape {

 

double Area {get; }

// Площадь

double Volume {get; }

// Объем

Перечисления и структуры

313

 

 

}

Реализовать такой интерфейс можно с помощью разных классов и структур. Например, параллелепипед имеет площадь поверхности (Area) и объем (Volume). Те же свойства имеются у любой трехмерной геометрической фигуры. Реализовать тот же интерфейс можно и в классе двумерных фигур. В этом случае объем будет равен нулю.

Определим статический метод с заголовком:

static void information (IShape sh)

Его назначение – вывести данные об объекте, ссылка на который используется в качестве аргумента. Тип параметра – это интерфейс, поэтому метод сможет обрабатывать объекты любых типов, реализующих интерфейс IShape.

В следующей программе определены две структуры, реализующие интерфейс IShape. Первая из них Circle – представляет круги с заданными значениями радиусов, вторая Sphere

– сферы с заданными значениями радиуса. Метод information() выводит сведения об аргументе. Текст программы:

// 15_12.cs структуры и интерфейсы using System;

interface IShape

{

double Volume { get; }

// Объем

double Area { get; }

// Поверхность

}

struct Circle : IShape // Круг

{

public double radius;

public Circle(double radius) // Конструктор { this.radius = radius; }

public double Area { get { return Math.PI * radius * radius; } }

public double Volume { get { return 0; } } // Объем

}

struct Sphere : IShape // Сфера

{

public double radius;

public Sphere(double radius) // Конструктор { this.radius = radius; }

314

Г л а в а 1 5

 

 

public double Area

// Поверхность

{ get { return 4 * Math.PI * radius * radius; } } public double Volume // Объем

{ get { return 4 * Math.PI * radius * radius * radius / 3; }

}

}

class Program

{

static void information(IShape sh)

{

Console.Write(sh.GetType()); Console.WriteLine(":\t Area={0,5:f2};\t

Volume={1,5:f2}",

sh.Area, sh.Volume);

}

static void Main()

{

Circle ci = new Circle(25); information(ci);

Sphere sp = new Sphere(4); information(sp);

}

}

Результат выполнения программы:

Circle: Area=1963,50; Volume= 0,00

Sphere: Area=201,06; Volume=268,08

В методе Main() созданы объекты структур Circle и Sphere, которые в качестве аргументов передаются методу information(). Обратите внимание на отсутствие приведения типов в теле метода information(). Если бы его параметр имел тип object, то необходимо было бы выполнять преобразование к типу конкретного аргумента.

Как и классы, структура может реализовать одновременно несколько интерфейсов. Покажем на примере, как можно использовать эту возможность. Сначала объявим интерфейс такого вида:

interface IImage { void display();

double Measure {get;}

Перечисления и структуры

315

 

 

double BaseSize {set;}

}

Члены этого интерфейса могут быть реализованы по-разному, т. е. им можно придать самый разный смысл. Пусть свойство Measure – это максимальный линейный размер («размах») геометрической фигуры; свойство BaseSize – базовый линейный размер; display() – прототип метода, который выводит сведения о типе, реализовавшем интерфейс, и значения свойств Measure, BaseSize конкретного объекта. Такими типами в нашем примере будут структуры Cube и Square, представляющие соответственно объекты «куб» и «квадрат». Для куба базовый размер – ребро куба, максимальный размер – наибольшая диагональ. Для квадрата базовый размер – сторона квадрата, максимальный размер – его диагональ.

Предположим, что объекты этих структур мы хотим разместить в массиве и упорядочить элементы массива по убыванию значений свойства Measure. Для сортировки элементов массива можно применить метод Array.Sort(). Этот метод предполагает, что элементы массива сравниваются друг с другом с помощью метода CompareTo(). Прототип этого метода размещен в интерфейсе IComparable из пространства имен System. Метод CompareTo() уже определен для таких типов как int, char, string и т.д.. Однако для пользовательских типов, которыми будут структуры Cube и Square, этот метод нужно определять явно. Поэтому реализуем в указанных структурах интерфейс IComparable. Тем самым в каждой из этих структур с необходимостью появится такой нестатический метод:

public int CompareTo (object obj)

{

if (Measure <((IImage)obj).Measure) return +1; if (Measure ==((IImage)obj).Measure) return 0; else return -1;

}

Обратите внимание, что тип object параметра obj приводится к типу интерфейса IImage, который должны иметь элементы массива.

Напомним, что в коде метода Array.Sort() выполняются многократные обращения к методу CompareTo(), где сравниваются

316

Г л а в а 1 5

 

 

характеристики двух элементов сортируемого массива. Если характеристика (в нашем примере свойство Measure) вызывающего элемента-объекта находится в «правильном» отношении к характеристике объекта-параметра, то метод CompareTo() должен возвращать отрицательное значение. При нарушении «порядка» элементов возвращается положительное значение. Для элементов, одинаковых по характеристике сравнения, возвращается значение 0.

Программа с указанными структурами может быть такой:

// 15 _13.cs структуры и интерфейсы using System;

interface IImage

{

void display();

double Measure { get; } double BaseSize { set; }

}

struct Cube : IImage, IComparable // куб

{

double rib; // Ребро базовый размер public double Measure // Максимальный линейный

размер

{ get { return Math.Sqrt(3 * rib * rib); } } public double BaseSize { set { rib = value; } } public void display()

{

string form = "Размеры куба: ребро={0,7:f3}; размах={1,7:f3}";

Console.WriteLine(form, rib, Measure);

}

public int CompareTo(object obj)

{

if (Measure < ((IImage)obj).Measure) return +1; if (Measure == ((IImage)obj).Measure) return 0; else return -1;

}

}

struct Square : IImage, IComparable // Квадрат

{

double side; // Сторона - базовый размер public double Measure // Максимальный линейный

Перечисления и структуры

317

 

 

размер

{ get { return Math.Sqrt(2 * side * side); } } public void display()

{

string form = "Размеры квадрата: сторона={0,7:f3}; размах={1,7:f3}";

Console.WriteLine(form, side, Measure);

}

public double BaseSize { set { side = value; } } public int CompareTo(object obj)

{

if (Measure < ((IImage)obj).Measure) return +1; if (Measure == ((IImage)obj).Measure) return 0; else return -1;

}

}

class Program

{

static void Main()

{

Cube cube = new Cube(); cube.BaseSize = 5; Square sq = new Square(); sq.BaseSize = 5;

Cube cube1 = new Cube(); cube1.BaseSize = 7;

IImage[] arIm = new IImage[] { cube, sq, cube1 }; Array.Sort(arIm);

foreach (IImage memb in arIm) memb.display();

}

}

Результаты выполнения программы:

Размеры куба: ребро= 7,000; размах= 12,124 Размеры куба: ребро= 5,000; размах= 8,660 Размеры квадрата: сторона= 5,000; размах= 7,071

В методе Main() определены два экземпляра структуры Cube и один экземпляр структуры Square. С помощью свойства BaseSize заданы значения базовых размеров структур. Объявлен и инициализирован массив типа IImage[]. Ссылка на него

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