Скачиваний:
64
Добавлен:
24.03.2015
Размер:
267.26 Кб
Скачать

15.3. Структуры

Структуры во многом похожи на классы, но имеют и существенные отличия. Как и класс, структура вводит тип. Однако, в отличие от классов структуры не могут участвовать в наследовании и поэтому в декларации структуры отсутствует спецификация базы.

Определение (иначе декларация или объявление) структуры (структурного типа) имеет следующий формат (указаны не все части полного формата):

модификаторы_структурыорt

struct имя_структуры интерфейсы_структурыopt

тело_ структуры

В декларации структуры struct - служебное слово, имя_структуры – выбранный программистом идентификатор, определяющий имя структурного типа. Тело_структуры – заключенная в фигурные скобки последовательность объявлений (деклараций) членов структуры. Модификаторов структуры меньше чем модификаторов класса. Могут использоваться: new, public, protected, internal, private.

Модификаторы определяют статус доступа структурного типа и они практически все уже рассмотрены в связи с классами.

Структуры не участвуют в наследовании, однако, структуры могут служить реализацией интерфейсов, перечисленных в декларации после имени структуры. Элемент декларации интерфейсы_структурыoptэто список интерфейсов, перед которым помещено двоеточие.

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

Структуры всегда наследуются от System.ValueTyре, которой в свою очередь является производным классом от System.Object. Поэтому в структурах присутствуют уже рассмотренные ранее открытые и защищенные методы класса Object. Напомним основные из них: ToString(), GetHashCode(), Equals(), GetType().

Существенным отличием структур от классов является то, что класс вводит тип ссылок, а структура - тип значений. Таким образом, каждой переменной структурного типа соответствует конкретный экземпляр структуры. И, присвоив новой переменной значение другой переменной, уже связанной с объектом структурного типа, мы получим еще одну копию объекта. Прежде чем привести пример, отметим ещё некоторые отличия структур от классов. Во-первых, в объявлении поля структуры нельзя использовать инициализатор. Во-вторых, в каждое объявление структуры автоматически встраивается конструктор умолчания без параметров. Назначение этого конструктора - инициализировать все члены структуры значениями, которые соответствуют их типам по умолчанию. В-третьих, в структуре нельзя явно объявить конструктор умолчания без параметров. В качестве иллюстрации возьмем класс "точка на плоскости" и эквивалентную ему структуру:

// 15_07.cs - структуры и классы "точка на плоскости"

class PointC // класс

{

double x = 10, y = 20;

public PointC() { y -= 5; }

public double X { get { return x; } set { x = value; } }

public double Y { get { return y; } set { y = value; } }

}

struct PointS // структура

{

//double x = 10, у = 20; // Error!

//public PointS() { y -= 5; } // Error!

double x, y;

public double X { get { return x; } set { x = value; } }

public double Y { get { return y; } set { y = value; } }

}

static void Main()

{

PointC pc = new PointC();

PointC pc1 = pc;

pc1.X = 10.2;

Console.WriteLine("X={0}; Y={1}", pc.X, pc.Y);

PointS ps = new PointS();

PointS ps1 = ps;

ps1.X = 10.2;

Console.WriteLine("X={0}; Y={1}", ps.X, ps.Y);

}

Результат выполнения программы: X=10,2; Y=15 X=0; Y=0

В классе PointC выполняется явная инициализация полей х, у. Конструктор умолчания PointC() изменяет значение поля у.

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

В программе рс - имя ссылки, ассоциированной с объектом класса PointC. В противоположность этому ps - имя переменной, значением которой является объект типа Points. Объявив ещё одну ссылку pc1 типа PointC и присвоив ей значение рс, мы связываем две ссылки с одним объектом класса PointC. Квалифицированные имена рс.Х и pc1.X обеспечивают доступ к одному и тому же свойству одного и того же объекта класса PointC.

Выполнение присваивания Points ps1 = ps; приводит к созданию копии структуры, представляемой переменной ps. Таким образом, после выполнения присваивания квалифицированные имена ps.X и ps1.X именуют свойства независимых друг от друга объектов одного структурного типа Points.

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

Копирование структуры выполняется не только при выполнении присваивания переменных структурного типа, но и при их использовании в качестве передаваемых по значениям параметров методов. Следующая программа иллюстрирует особенности применения структур в методах.

// 15_08.cs - структуры и методы

struct PointS // структура

{

double x, y;

public double X { get { return x; } set { x = value; } }

public double Y { get { return y; } set { y = value; } }

public PointS(double xi, double yi) { x = xi; y = yi; }

}

static PointS reverse(PointS dot)

{

dot.X = -dot.X;

dot.Y = -dot.Y;

return dot;

}

public static void Main()

{

PointS one = new PointS(12, 8);

PointS two = reverse(one);

Console.WriteLine("one.X={0}; one.Y={1}", one.X, one.Y);

Console.WriteLine("two.X={0}; two.Y={1}", two.X, two.Y);

}

Результат выполнения программы: one.X=12; one.Y=8 two.X=-12; two.Y=-8

В программе объявлен структурный тип Points. В нём два закрытых поля (х,у), два ассоциированных с этими полями открытых свойства (X,Y) и открытый конструктор общего вида. В классе Program два статических метода. Первый из них reverse() получает в качестве передаваемого по значению параметра структуру, изменяет с помощью свойств значения её полей х и у, и возвращает структуру как результат в точку вызова метода.

В методе Main() объявлены две переменные Points one и Points two. Первая из них связана со структурой, инициализированной обращением к конструктору PointS(12,8). Вторая получает в качестве значения результат, возвращаемый методом reverse(one).

Очень важен тот факт, что после выполнения метода reverse(), аргументом которого служит объект one, значение этого объекта не изменилось. Это подтверждает тот факт, что при присваивании структур, при использовании структуры в качестве передаваемого по значению параметра или возвращаемого методом значения создаётся копия структуры, в дальнейшем полностью независимая от оригинала.

Если в рассмотренной программе заменить структуру на класс (т.е. заменить struct PointS на class PointC), то результат выполнения программы будет таким:

one.X=-12; one.Y=-8

two.X=-12; two.Y=-8

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

static Points reverse(ref Points dot).

Соответствующим образом изменится вызов метода:

two = reverse(ref one);

Как уже сказано, в структурах нельзя инициализировать поля в их объявлениях. Кроме того, нельзя явным образом определить конструктор без параметров. Все поля объектов структурного типа без вмешательства извне инициализируются умалчиваемыми значениями, соответствующими типам полей. Например, для арифметических типов это нули, для ссылок null. Например, объявим ссылку на массив структур и определим массив:

Points[ ] аr = new Points[50];

Элементами массива в этом примере станут структуры, для которых поля х и у будут иметь нулевые значения.

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

Следующая программа иллюстрирует приведённые сведения о структурах.

// 15_09.cs - структуры, конструктор умолчания

struct PointS // структура

{

double x, y;

public double X { get { return x; } set { x = value; } }

public double Y { get { return y; } set { y = value; } }

}

public static void Main()

{

PointS[] ar = new PointS[50];

Console.WriteLine("ar[0].X={0}; ar[0].Y={1}", ar[0].X, ar[0].Y);

PointS three = new PointS();

three.Y = 2.34;

Console.WriteLine("three.X={0}; three.Y={1}", three.X, three.Y);

PointS four; // неинициализированная переменная!

four = three;

Console.WriteLine("four.X={0}; four.Y={1}", four.X, four.Y);

}

Результат выполнения программы: ar[0].X=0; ar[0].Y=0 three.X=0; three.Y=2,34 four.X=0; four.Y=2,34

Так как структура вводит тип значений, то использование структур вместо классов в ряде случаев повышает быстродействие программ и уменьшается объём занимаемой памяти. Связано это с тем, что доступ к объекту классавыполняется косвенно, а обращение к структуре - непосредственно. Имя экземпляра структуры является именем переменной, значением которой служит объект структурного типа.

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

Соседние файлы в папке Lekc_C#