112.14K
Category: programmingprogramming

Структуры. Массивы структур. Лекция 20

1.

Лекция 20
Структуры. Массивы
структур

2.

Структуры
Структура (struct) - это простой
определяемый пользователем тип,
являющийся облегченной
альтернативой классам. Структуры
аналогичны классам в том смысле, что
могут иметь конструкторы, свойства,
методы, поля различного типа,
операторы, вложенные типы и
индексаторы.

3.

Структуры
Между структурами и классами существует
много различий.
Более важное различие состоит в том, что
классы относятся к ссылочным типам, а
структуры - к размерным типам и для них не
требуется выделение памяти из кучи.
Переменная с типом структуры непосредственно
содержит данные этой структуры, в то время как
переменная с типом класса содержит ссылку на
данные, которые считаются объектом.

4.

Синтаксис определения структуры
[атрибуты] [модификаторы_структуры]
[partial] struct идентификатор
[список_параметров_типа]
[:список_интерфейса]
[предложения_ограничений_параметров_
типа]
{элементы-структуры} [;]

5.

Модификаторы структуры
new
определение структуры (в стеке)
public
(открытые), доступны любому
методу любого класса
protected (защищенные), доступны
методам класса А и методам классов,
производных от класса А
internal
(внутренние), доступны методам
любого класса в сборке класса А
private
(закрытые), доступны только
методам класса А

6.

Структуры
Модификатор partial указывает, что объявление
структуры является объявлением частичного типа.
Объявление структуры может содержать
спецификацию список_интерфейса, в этом случае
считается, что в структуре непосредственно
реализованы заданные типы интерфейсов.
Тело_структуры содержит определение членов
структуры в фигурных скобках.
{ [элементы_структуры] }

7.

Структуры
К элементам структуры относятся члены,
включенные в структуру и члены, унаследованные
из System.ValueType - объявление:
- константы
- поля
- метода
- свойства
- события
- индексатора
- оператора
- конструктора
- статического конструктора
- типа

8.

Структуры
Объявление каждого поля-члена структуры
имеет следующий вид:
<уровень_доступа> <тип> <имя>;
Например:
struct route {
public orientation direction;
public double distance;
}

route myRoute;
myRoute.distance = 2.5;

9.

Пример 1
class Program {
static void Main(string[] args) {
route myRoute; // создание переменной типа структура
int myDirection = -1;
double myDistance;
Console.WriteLine("l) North\n2) South\n3) East\n4)
West");
do {
Console.WriteLine("Выберите направление
(Select a direction):");
myDirection =
Convert.ToInt32(Console.ReadLine());
} while ((myDirection < 1) || (myDirection > 4));

10.

Пример 1
Console.WriteLine ("Введите расстояние (Input a
distance): ") ;
myDistance =
Convert.ToDouble(Console.ReadLine ());
myRoute.direction = (orientation)myDirection;
myRoute.distance = myDistance;
Console.WriteLine ("myRoute указывает
направление (specifies a direction of) {0} и (and a) "
+ " расстояние (distance of) {1}", myRoute.direction,
myRoute.distance);
Console.ReadKey();
}
}
}

11.

Пример 1
namespace Ch05Ex03 {
enum orientation : byte {
north = 1,
south = 2,
east = 3,
west = 4
}
struct route {
public orientation direction;
public double distance;
}

12.

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

13.

Несколько важных отличий от классов
1. Структуры являются типами значения.
2. Все типы структур неявным образом
наследуются из класса System.ValueType.
3. При присваивании переменной с типом
структуры создается копия присваиваемого
значения.
4. Значением по умолчанию для структуры
является значение, при котором все поля типов
значения устанавливаются в соответствующие
значения по умолчанию, а все поля
ссылочного типа — в значение null.

14.

Несколько важных отличий от классов
5. Операции упаковки и распаковки
используются для выполнения преобразования
между типом структуры и объектом object.
6. Ключевое слово this в структурах имеет
другой смысл.
7. Объявления полей экземпляров для структуры
не могут включать инициализаторы
переменных.
8. В структуре не разрешается объявлять
конструктор экземпляров без параметров.
9. В структуре не может быть объявлен
деструктор.

15.

Несколько важных отличий от классов
1. Структуры являются типами значения.
struct Node{
int data;
Node next; // ошибка
}
struct A { B b; } // ошибка, поскольку
struct B { C c; } // типы A, B и C
struct C { A a; } // зависят друг от друга

16.

Несколько важных отличий от классов
2. Все типы структур неявным образом наследуются из
класса System.ValueType.
Класс System.ValueType, в свою очередь, наследуется из
класса object.
В отличие от классов, структуры не поддерживают
наследование. Они являются неявными потомками класса
Object, но не могут наследовать ни от какого другого класса или
структуры. Однако подобно классам структуры могут
реализовывать любое число интерфейсов.
В объявлении структуры не допускаются модификаторы
abstract и sealed, член структуры не может иметь объявленный
уровень доступа protected или protected internal.
Функции-члены в структуре не могут иметь модификаторы
abstract или virtual, а модификатор override допускается только
для переопределения методов, унаследованных из класса
System.ValueType.

17.

Несколько важных отличий от классов
3. При присваивании переменной с типом структуры
создается копия присваиваемого значения.
Когда одна структура присваивается другой, создается
копия объекта структуры из правой части оператора
присваивания и эта копия присваивается переменной
другой структуры, находящейся в левой части оператора
присваивания.
В отличие от этого при выполнении присваивания в
переменную с типом класса копируется ссылка, а не сам
объект, на который указывает эта ссылка.
Аналогичным образом при передаче структуры в
качестве параметра по значению или возвращения ее
в результате выполнения функции-члена создается копия
структуры. Структура может передаваться в функциючлен по ссылке с использованием параметра ref или out.

18.

Пример 2
using System;
struct MyStruct {
public int x;
}
class StructAssignment {
static void Main() {
MyStruct a; // создание переменной типа структура
MyStruct b;
a.x = 10;
b.x = 20;
Console.WriteLine("a.x {0}, b.x {1}", a.x, b.x); // а.х 10, b.x 20
a = b; // копирование структуры
b.x = 30;
Console.WriteLine("a.x {0}, b.x {1}", a.x, b.x); // a.x 20, b.x 30
}
}

19.

Пример 3
using System;
class MyClass {
public int x;
}
class ClassAssignment {
static void Main() {
MyClass a = new MyClass();
MyClass b = new MyClass();
a.x = 10;
b.x = 20;
Console.WriteLine("a.x {0}, b.x {1}", a.x, b.x); // а.х 10, b.х 20
a = b;
b.x = 30;
Console.WriteLine("a.x {0}, b.x {1}", a.x, b.x); // а.х 30, b.х 30
}
}

20.

Несколько важных отличий от классов
4. Значением по умолчанию для структуры
является значение, при котором все поля
типов значения устанавливаются в
соответствующие значения по умолчанию,
а все поля ссылочного типа — в значение
null.
struct Point {
public int x;
public int y;
}

Point[] a = new Point[100]; // x = 0, y = 0

21.

Несколько важных отличий от классов
4.
using System;
struct KeyValuePair {
string key;
string value;
public KeyValuePair(string key, string value) {
if (key == null || value == null)
throw new ArgumentException();
this.key = key;
this.value = value;
}
}

22.

Несколько важных отличий от классов
5. Операции упаковки и распаковки используются для
выполнения преобразования между типом структуры и
объектом object.
При преобразовании значения с типом структуры в тип object
или в тип интерфейса, реализуемый этой структурой,
происходит операция упаковки. Точно так же при обратном
преобразовании выполняется операция распаковки. При
упаковке и распаковке выполняется копирование значения
структуры в упакованный экземпляр или из такого экземпляра.
Если в структуре переопределяется виртуальный метод,
унаследованный из класса System.Object (например, Equals,
GetHashCode или ToString), вызов этого виртуального метода в
экземпляре типа структуры не ведет к выполнению упаковки.
Это правило действует даже в том случае, когда структура
используется в качестве параметра типа и вызов происходит в
экземпляре с типом параметра типа.

23.

Пример 4
using System;
struct Counter {
int value;
public override string ToString() {
// переопределенный виртуальный метод
value++;
return value.ToString();
}
}
Для методов в структурах ключевое слово
static не требуется!

24.

Пример 4
class Program {
static void Test<T>() where T: new() {
// обобщенный метод – шаблон
T x = new T();
Console.WriteLine(x.ToString());
Console.WriteLine(x.ToString());
Console.WriteLine(x.ToString());
}
static void Main() {
Test<Counter>();
}
}

25.

Пример 5
using System;
interface ICounter{ // интерфейс
void Increment();
}
struct Counter: ICounter { // структура использует интерфейс
int value;
public override string ToString() {
return value.ToString();
}
void ICounter.Increment(){// определение метода интерфейса
value++;
}
}

26.

Пример 5
class Program {
static void Test<T>() where T: ICounter, new() {
// обобщенный метод
T x = new T();
Console.WriteLine(x);
x.Increment();
// изменение x
Console.WriteLine(x);
((ICounter)x).Increment(); // изменение
// упакованной копии x
Console.WriteLine(x);
}
static void Main() {
Test<Counter>();
}
}

27.

Несколько важных отличий от классов
6. Ключевое слово this в структурах имеет
другой смысл.
В классе ключевое слово this классифицируется
как значение, т. о., присваивание для this в
функции-члене класса недоступно.
В конструкторе экземпляра структуры ключевое
слово this соответствует параметру out типа
структуры, а в функции-члене экземпляра
структуры ключевое слово this соответствует
параметру ref типа структуры. В обоих случаях this
считается переменной, что позволяет изменить всю
структуру, для которой была вызвана эта функциячлен, путем присваивания в this или передачи this в
качестве параметра ref или out.

28.

Пример 6
struct Point{
public int x, y;
public Point(int x, int y) { // конструктор
this.x = x;
this.y = y;
}
}
class Test{
static void Main() {
int xxx, yyy, ii=0;
Point[] points = new Point[100]; // массив структур
for (int i = 0; i < 100; i++) points[i] = new Point(i, i);

29.

Пример 6
foreach (Point si in points) {
si.SiPoint(out xxx, out yyy);
Console.WriteLine("points[" + ii + "].x = " + xxx);
Console.WriteLine("points[" + ii + "].y = " + yyy);
Console.WriteLine();
ii++;
}
}
}
Создается только один экземпляр объекта для массива.
Экземпляры Point хранятся встроенными в массив.
Конструктор структур вызывается с помощью
оператора new, однако при этом не предполагается
выделение памяти.

30.

Несколько важных отличий от классов
7. Объявления полей экземпляров для
структуры не могут включать
инициализаторы переменных.
Объявления полей экземпляра не могут
содержаться инициализаторы переменных.
Статические поля структуры могут содержать
инициализаторы переменных.
struct Point{
public int x = 1; // ошибка
public int y = 1; // ошибка
}

31.

Несколько важных отличий от классов
8. В структуре не разрешается объявлять
конструктор экземпляров без параметров.
struct Point{
int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}

Point p1 = new Point(); // x = 0, y = 0
Point p2 = new Point(0, 0); // x = 0, y = 0

32.

Несколько важных отличий от классов
9. В структуре не может быть объявлен деструктор.
Структуры задумывались как простые и облегченные
конструкции языка. В то время как закрытые элементы
(например, в свойствах - методы get и set)
способствуют сокрытию данных и инкапсуляции,
некоторые программисты полагают, что для структур
это излишне. Другие программисты считают, что
свойства обеспечивают ясный и простой интерфейс и
что хороший стиль программирования требует
сокрытия данных даже в случае простых облегченных
объектов. Какую из двух стратегий выбрать - вопрос из
области философии разработки программного
обеспечения.

33.

Пример 7
using System;
public struct Location {
public Location(int xCoordinate, int yCoordinate)
// конструктор
{
xVal = xCoordinate;
yVal = yCoordinate;
}

34.

Пример 7
public int x{ // открытое свойство
get
{ // закрытый метод, возвращающий
// значение закрытого поля
return xVal;
}
set
{ // закрытый метод, инициализирующий
// закрытое поле
xVal = value;
}
}

35.

Пример 7
public int у // свойство
{
get { return yVal; }
set { yVal = value; }
}
public override string ToString() {
// переопределенный виртуальный метод
return (String.Format("{0}, {1}", xVal, yVal));
}
private int xVal;
private int yVal;
}

36.

Пример 7
public class Tester
{
public void myFunc(Location loc)
// передача структуры в функцию по значению
{
loc.x = 50;
loc.у = 100;
Console.WriteLine("В MyFunc координаты
Loc1: {0}", loc);
// неявно выполняется метод ToString
}

37.

Пример 7
static void Main() {
Location loc1 = new Location(200,300);
Console.WriteLine("Координаты Loc1:
{0}", loc1); // неявно выполняется метод ToString
Tester t = new Tester();
t.myFunc(loc1);
Console.WriteLine("Координаты Loc1:
{0}", loc1); // неявно выполняется метод ToString
}
}

38.

Пример 7
using System;
public struct Location { … }
public class Tester {
static void Main() {
Location lod; // вызов конструктора отсутствует
lod.xVal = 75; // инициализация элементов
lod.yVal = 225;
lod.x = 300; // использование свойства
lod. у = 400; // использование свойства
Console. WriteLine(lod);
}
}

39.

Пример 7
struct Point{
int x, y;
public int X { // свойство
set { x = value; }
}
public int Y { // свойство
set { y = value; }
}
public Point(int x, int y) {
X = x; // ошибка, значение не определено
Y = y; // ошибка, значение не определено
}
}

40.

Пример 8
using System;
struct Book {
public string Author;
public string Title;
public int Copyright;
public Book(string a, string t, int c) {
Author = a;
Title = t;
Copyright = c;
}
}

41.

Пример 8
class StructDemo {
static void Main() {
int ch = 0, a, k, i;
string aut, tit, s;
// массив структур,
// вызов конструктора по умолчанию
Book [] books = new Book [100];
Book bo; // создание переменной
// без вызова конструктора

42.

Пример 8
for ( ; ; ) {
do { Console.Clear();
Console.WriteLine("1. Ввод данных");
Console.WriteLine("2. Поиск книги");
Console.WriteLine("3. Выход");
Console.WriteLine("Выберите пункт меню");
s = Console.ReadLine();
if (s != "") ch = Convert.ToInt32(s);
else ch = 0;
} while(ch != 1 && ch != 2 && ch != 3);

43.

Пример 8
switch(ch) {
case 1: for (i = 0; i < 100; i++) {
Console.Write( "Автор - ");
aut = Console.ReadLine();
if (aut == "") break;
Console.Write( "Название книги - ");
tit = Console.ReadLine();
if (tit == "") break;
Console.Write( "Количество страниц - ");
s = Console.ReadLine();
if (s == "") break;
a = Convert.ToInt32(s);
books [i] = new Book (aut, tit, a);
}
break;

44.

Пример 8
case 2:
Console.Write( "Автор - ");
aut = Console.ReadLine();
k = 0;
Console.WriteLine("Книги автора " + aut + ":");
aut = aut.Trim().ToUpper();
foreach (Book b in books){
bo.Author = b.Author;
if (bo.Author != null) bo.Author =
bo.Author.Trim().ToUpper();
if (aut == bo.Author) {
Console.WriteLine((k+1) + ": " + b.Title + ", (c) "
+ b.Copyright);
k++;
}
}

45.

Пример 8
if (k == 0) Console.WriteLine("Нет в наличии.");
Console.ReadKey(); // остановка экрана
break;
case 3: Environment.Exit(0);
break;
} // end switch(ch)
} // end for ( ; ; )
}
}

46.

Контрольные вопросы
1. Какие элементы могут быть
членами структуры?
2. Каковы отличия структуры от
классов?

47.

Домашнее задание
Создайте программу – игру «Угадай
символ», в которой первый игрок вводит
числа в диапазоне от 33 до 127,
являющиеся кодами 20-ти символов, а
второй игрок пытается угадать символы
из таблицы ANSI, коды которых введены
первым игроком. Для хранения данных,
используйте тип данных «множество».
English     Русский Rules