русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

Значимые и ссылочные переменные


Дата добавления: 2013-12-23; просмотров: 1692; Нарушение авторских прав


Классы и объекты

Превращение в класс

Public void PersonAnalyze()

06 {

if (Height-Weight>100.0)

Console.WriteLine(Name+" полный");

07 else Console.WriteLine(Name + " худой");

08 }

09 }

10 class Program

11 { static void Main(string[] args)

12 { Person me, you;

13 me.Name = "”Это я"; me.Height = 190.0; me.Weight=85;

14 you.Name="Это ты"; you.Height=140.0; you.Weight=85;

15 me.PersonAnalyze();

16 you.PersonAnalyze();

17 }

18 }

Первое, что следует отметить – метод PersonAnalyze стал частью структурного типа Person. При этом в его описании исчезло слово static. Это означает, что вызов метода будет осуществляться структурной переменной этого типа. В стр. 15 и 16 мы видим два таких вызова. Важно, что в методе PersonAnalyze пропали параметры. Когда переменная me вызывает метод PersonAnalyze, нет необходимости также передавать дополнительные данные через параметры – необходимые величины находятся в полях структурного типа и доступны методу. Кроме того, вызовы me.PersonAnalyze и you.PersonAnalyze дадут различные результаты, поскольку используют различные данные двух различных структур.

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

Наконец, рассмотрим последнюю модификацию программы.

01 class Person

02 { public string Name;

03 public double Height;

04 public double Weight;

05 public void PersonAnalyze()

06 { if (Height-Weight>100.0) Console.WriteLine(Name+" худой ");

07 else Console.WriteLine(Name + " полный ");

08 }

09 }

10 class Program

11 { static void Main(string[] args)

12 { Person me;

13 me = new Person();



14 Person you = new Person();

15 me.Name="Это я"; me.Height=190.0; me.Weight=85;

16 you.Name="Это ты"; you.Height=140.0; you.Weight=85;

17 me.PersonAnalyze();

18 you.PersonAnalyze();

19 }

20 }

Во-первых, в заголовке структурного типа слово struct заменено ключевым словом class. Как следствие, в методе Main уже недостаточно только описать переменые. Переменные, порождаемые на основании класса, называются объектами и требуют обязательного создания с помощью операции new. Мы видим, что эту операцию можно выполнить в отдельном операторе присваивания (стр.13) и в момент описания переменной с инициализацией (стр.14).

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

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

Далее можно обращаться к переменным объекта и вызывать методы объекта. Обратите внимание на словосочетание «переменные объекта» - действительно, каждый объект класса имеет свой собственный комплект переменных, описанных в его классе. Множество значений переменных объекта можно называть состоянием объекта. Иначе обстоит дело с методами – они существуют в одном экземпляре и все объекты класса пользуются методами «сообща». Множество методов определяет поведение объектов класса.

В C# все переменные можно разделить на две категории – переменные значимого и ссылочного типа.

Значимая переменная хранит свое значение непосредственно в выделенной ей компилятором памяти. Структуры являются значимыми переменными, поэтому размещение в памяти переменной me в вариантах программ, где она была структурой, выглядит так:

Значимыми являются также переменные основных встроенных типов данных – числовые (double, int), символьные (char), логические (bool). А вот переменные строкового типа (String) – ссылочные.

Ссылочная переменная в своей памяти хранит адрес (ссылку) на другое место в памяти, где хранятся данные. Помимо решения проблем с передачей изменяемых параметров, эта двухуровневая схема адресации в большей степени соответствует духу объектно-ориентированного подхода. Вспомним вариант программы, где me была объектом класса Person. Переменные, предназначенные для указания на объекты классов, являются ссылочными переменными, поэтому схема размещения в памяти такова:

Теперь размер памяти, выделяемой любой ссылочной переменной, одинаков – это размер, достаточный для хранения адреса. Данные, сгруппированные в виде информационного объекта, находятся в том месте, на которое указывает адрес. Теперь становится понятнее, зачем объекты необходимо создавать с помощью операции new. Компилятор не занимается выделением памяти для объектов. Эта операция должна быть выполнена динамически, то есть во время выполнения программы. Если Вы забудете осуществить выделение памяти операцией new и начнете использовать такую переменную, то в программе произойдет ошибка времени выполнения «null reference».

Уточним, какие переменные в C# являются значимыми, а какие – ссылочными.

Значимые переменные Ссылочные переменные
Переменные встроенных типов Структуры, не использующие для создания операцию new Массивы Структуры, создаваемые с помощью new Объекты класса String Объекты классов

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

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

Разместим в классе Program рядом с методом Main еще один метод Grow, увеличивающий рост человека, переданного в качестве параметра:

public static void Grow(Person p) //этот метод мог быть проще

{Person local; local=p; local.Weight++;}

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

Перед вызовом этого метода в Main должен быть создан объект Person.

Person me = new Person();

me.Name = "Это я"; me.Height = 190.0; me.Weight = 85;

Далее осуществляется вызов метода Grow:

Grow(me);

В процессе выполнения метода Grow создается локальная переменная local, которая, благодаря присваиванию local=p; также ссылается на объект Person.

После выполнения метода Grow переменная local исчезает, однако объект Person в памяти остается и к нему имеется возможность доступа через переменную me. Таким образом, благодаря ссылочным переменным легко решается проблема изменяемых параметров.

Теперь зададим себе вопрос – что если переменная me также исчезает, освобождая занимаемую ею память? В этом случае становится невозможным доступ к объекту Person, занимающему свой участок памяти. В этой ситуации возникает опасность “утечки памяти” - в процессе выполнения программы может возникнуть много неиспользуемых объектов. В некоторых языках решение этой проблемы возлагалось на программиста. Он должен был предусмотреть явное уничтожение объекта специальным методом-деструктором.

Однако в современных языках, в частности и в C#, используется другой подход. Во время выполнения программы в фоновом режиме выполняется специальная утилита – сборщик мусора (garbage collector), который автоматически уничтожает объекты, для которых не осталось ссылок в программе.

Отметим еще несколько особенностей.

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

Операции сравнения для ссылочных переменных обычно реализованы как сравнение адресов объектов, на которые они ссылаются. Поэтому имеют смысл обычно только операции == (равно) и != (не равно). Однако есть возможность самостоятельно переопределить операции сравнения для реализации более содержательного сравнения, основанного на состоянии объекта.

Механизм скрытой передачи адреса на объект решает большую часть проблем, возникающих при передаче параметров. В языке C и его «наследниках» передача параметров (то есть передача значений фактических параметров в формальные переменные) осуществляется только по значению. В этом случае функция, которая «возвращает» результат своей работы через один или несколько параметров, должны были как-то обходить это правило. Понятно, что значимые переменные уже обладают такой способностью. Однако некоторые ситуации таким способом не учитываются.

Сначала рассмотрим две следующие ситуации:

1) Необходимо обеспечит передачу «по ссылке» значимой переменной.

2) Необходимо обеспечить изменение методом самой ссылки (адреса).

В обеих ситуациях можно воспользоваться специальным видом параметров – ref-параметрами. Для этого нужно указать ключевое слово ref в заголовке метода перед определением формального параметра и при вызове метода перед именем фактического параметра:

public void DoSomething(ref Person p, ref int i)

{ Person newMe= new Person();

newMe.Name="Это я"; newMe.Height=190.0; newMe.Weight=85;

me=newMe;

. i++;

}

. . .

int k=5;

DoSomething(ref me, ref k);

Здесь в методе DoSomething обеспечивается передача по ссылке как ссылочной переменной me типа Person, так и значимой переменной k типа int. Благодаря этому, после вызова метода переменная me ссылается на новый объект, а переменная k изменяет свое значение.

Еще одна ситуация, представляющая интерес - передача в метод неинициализированные переменные.

Инициализация переменных перед их использованием является обязательным требованием C#. Таким образом, компилятор следит за тем, чтобы ссылочные переменные в момент их использования указывали на некоторый объект. В противном случае они считаются неинициализированными и имеют специальное знначнение null. Однако в некоторых случаях это требование становится неудобным. Что, если первоначальное значение для переменной может быть определено только в результате выполнения достаточно сложного метода? В этом случае нужно использовать специальные out-параметры. Ключевое слово out следует указывать, как и слово ref перед формальными и фактическими параметрами.

class Program

{ static void Main(string[] args)

{ Person me;

MakePerson(out me);

me.PersonAnalyze();

}

public static void MakePerson(out Person p)

{ p = new Person();

p.Name="Это я"; p.Height=190.0; p.Weight=85;

}

}

Здесь мы видим, что переменная me, описанная в методе Main, используется в качестве параметра метода MakePerson. На момент вызова эта переменная не ссылается на некоторый созданный объект. Для ссылочных переменных это и означает, что переменная не инициализирована. Однако создание объекта и связывание его с переменной успешно происходит методе MakePerson с out-параметром.

Для значимых переменных использование out-параметров не столь важно, поскольку значимые переменные инициализируются автоматически нулевыми значениями.



<== предыдущая лекция | следующая лекция ==>
Помещаем метод в структурный тип | Статические элементы


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.005 сек.