Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Ответы_ТП

.pdf
Скачиваний:
9
Добавлен:
21.05.2015
Размер:
880.4 Кб
Скачать

1.2. Для констант можно использо вать только спецификаторы 1 -6.

Специфика

Описание

тор

 

new

Новое описание поля, скрывающее

 

унаследованный элемент класса

 

 

public

Доступ к элементу не ограничен

 

 

protected

Доступ только из данного и производных

 

 

internal

Доступ только из данной сборки

 

 

protected

Доступ только из данного и производных

internal

классов и из производных классовданной сборки

 

private

Доступ только из данного класса

static

Одно поле для всех экземпляров класса

readonly

Поле доступно только для чтения

volatile

Поле может изменяться другим процессом или

По умолчанию элементы класса считаются закрытыми ( private). Для полей клас са этот вид доступа является предпочтительным, поскольку ноля определяют внутреннее строение класса, которое должно быть скрыто от пользователя. Все методы класса имеют непосредственный доступ к его закрытым полям.

105

Поля, описанные со спецификатором static, а также константы существуют в един ственном экземпляре для всех объектов класс а, поэтому к ним обращаются не через имя экземпляра, а через имя класса. Если класс содержит только статические эле менты, экземпляр класса создавать не требуется.

Обращение к полю класса выполняется с помощью операции доступа

(точка). Справа от точки зад ается имя поля, слева — имя экземпляра для обычных нолей или имя класса для статических. В листинге 1.1 приведены пример простого класса Demo и два способа обращения к его полям.

Л и с т и н г 1 . 1 . Класс Demo, содержащий поля и константу

using System;

namespace ConsoleApplication1

{

 

class Demo

 

{

 

publicint a = 1; //

полеДанных

public const double

с= 1.66; // константа

publicstaticstring s = "Demo" ;//статическоеполекласса

doubley;

//

закрытое поле данных

}

class Class1

{

static void Main()

{

Demox = newDemo();//создание экземпляра класса Demo

Console.WriteLine(x.a );//

x.a - обращение к полю класса

Console.WriteLine(Demo.c

);//Demo.c - обращение к константе

Console.WriteLine(Demo.s

); //обращение к статическому полю

}

 

}

 

}

 

Поле у вывести на экран аналогичным образом не удастся: оно является закрытым, то есть недоступно извне (из класса Classl). Поскольку значение этому полю явным образом не присвоено, среда присваивает ему значение ноль.

Все поля сначала автоматически инициализируются нулем

соответствующего т ипа (например, полям типа int присваивается 0, а ссылкам на объекты — значение null) . После этого полю присваивается значение, заданное при его явной инициа лизации. Задание начальных значений для статических полей выполняется при инициализации класса, а обычных — при создании экземпляра.

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

5. Делегаты

Делегат — это объект, который может ссылаться на метод. Создавая делегат, по сути, создаѐте объект, который может содержать ссылку на метод. Более того, этот метод можно вызватьпосредством соответствующей ссылки. Таким образом, делегат может вызывать метод,на который он ссылается.

Ссылка по существупредставляет собой а дрес памяти. Следовательно, ссылка на объект — это адрес объекта. Даже несмотря на то, что метод не является объектом, он тоже имеет отношениек физической области памяти, а адрес его точки входа — это адрес, к которому происходит обращение при вызове метод а. Этот адрес можно присвоить делегату. Если ужделегат ссылается на метод, этот метод можно вызвать посредством данного делегата.

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

Делегат объявляется с помощью ключевого слова delegate. Общая форма объявления делегата имеет следующий вид:

delegate тип_возврата имя(список_параметров);

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

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

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

using System;

// Объявляем делегат.

delegate string strMod(string str);

classDelegateTest {

// Методзаменяетпробелыдефисами

static string replaceSpaces(string a) {

Console.WriteLine("Замена пробелов дефисами.");

return a.Replace(' ', ' - ' ) ;

}

static string removeSpaces(string a) {// Метод удаляет пробелы.

string temp = "";

int i;

Console.WriteLin e("Удаление пробелов.");

for(i=0; i < a.Length; i++)

if (a[i] != ' f) temp += a[i] ;

return temp;

}

static string reverse(string a) {// Метод реверсирует строку, string temp = "";

int i, j;

Console.WriteLine("Реверсирование строки."); for(j=0, i=a.Length -1; i >= 0; i --, j++)

temp += a[i]; return temp;

}

public static void Main() {

strMod strOp = new strMod(replaceSpaces); // Создание делегата. stringstr;

// Вызываем методы посредством делегата. str = str0p("ЭTO простой тест.");

Console.WriteLine("Результирующая строка: " + str); Console.WriteLine();

strOp = new strMod(removeSpaces); str = strOp("Это простой тест.");

Console.WriteLine("Результирующая строка: " + str); Console.WriteLine();

strOp = new strMod(reverse);

str = strOp("Это простой тест.");

Console.WriteLine("Результирующая строка: " + str);

}}

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

Замена пробелов дефисами.

Результирующая строка: Это -простой-тест.

Удаление пробелов.

Результирующая строка: Этопростойтест.

Реверсирование строки.

Результирующая строка: .тсет йотсорп отЭ

Впрограмме объявляется делегат с именем strMod, который принимаетодин параметр типа string и возвращает string-значение. В классе DelegateTestобъявлены три статических метода, сигнатура которых совпадает с сигнатурой, заданной делегатом. Эти методы предназначены для модификации строк определенноговида. Обратите внимание на то, что метод replaceSpaces () для замены пробеловдефисами использует метод Replace () — один из методов класса string.

Вметоде Main () создается ссылка типа strMod с именем strOp, и ей присваивается ссылка на метод replaceSpaces(). Внимательно рассмотрите следующую строку:

strModstrOp = newstrMod(replaceSpaces);

Обратите внимание на то, что метод replaceSpaces() передается делегату в качестве параметра. Здесь используется только имя метода (параметры не указываются).Это наблюдение можно обобщить: при реализации делегата задается только имя метода, на который должен ссылаться этот делегат. Кроме того, объявление ме тода должно соответствовать объявлению делегата . В противном случае вы получите сообщение обошибке еще во время компиляции.

Затем метод replaceSpaces() вызывается посредством экземпляра

делегата сименем strOp, как показано в следующей строке:

str = strOp("Это простой т е с т . " ) ;

Поскольку экземпляр strOp ссылается на метод replaceSpaces(), то вызываетсяименно метод replaceSpaces(). Затем экземпляру делегата strOp присваиваетсяссылка на метод removeSpaces(), после чего strOp вызывается снова. На э тот развызывается метод removeSpaces ().

Наконец, экземпляру делегата strOp присваивается ссылка на метод reverse(), иstrOp вызывается еще раз. Это, как нетрудно догадаться, приводит к вызову метода reverse().

Главное в этом примере то, что вызов экземпляр а делегата strOp трансформируется в обращение к методу, на который ссылается strOp при вызове. Таким образом, решение о вызываемом методе принимается во время выполнения программы, а не впериод компиляции.

6. Деструкторы

Средства языка С# позволяют опреде лить метод, который должен вызываться непосредственно перед тем, как объект будет окончательно разрушен системой сбора мусора. Этот метод называется деструктором, и его можно использовать для обеспечения гарантии "чистоты" ликвидации объекта. Например, вы могли бы использовать деструктор для гарантированного закрытия файла, открытого некоторым объектом.

Формат записи деструктора такой:

~имя_класса() {

// код деструктора

}

Очевидно, что элемент имя_класса здесь означает имя класса. Таким образом, деструктор объявляется подобно конструктору за исключением того, что его имени предшествует символ "тильда" (~).

Чтобы добавить деструктор в класс, достаточно включить его как

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

using System;

class Destruct {

publicint x;

public Destruct(inti) {

x = i;

}

// Вызывается при утил изации объекта.

~Destruct() {

Console.WriteLine("Деструктуризация " + x) ;

}

//Метод создает объект, который немедленно

//разрушается.

public void generator(inti) {

Destruct o = new Destruct(i);

} }

classDestructDemo {

public static void Main() {

int count;

Destruct ob = new Destruct(0);

for(count=l; count < 100000; count++)

ob.generator(count);

Console.WriteLine(" Готово!");

}}

7. Доступ к членам класса и наследование

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

ктем из НИХ, которые объявлены закрытыми.

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

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

Защищенный член создается с помощью модификатора доступа protected. При объявлении protected-члена он, по сути, является закрытым, но с одним исключением. Это исключение вступает в силу, когда защищенный член наследуется. В этом случае защищенный член базового класса становится защищенным членом производного класса, а следовательно, и доступным для производного класса. Таким образом, используя модификатор доступа protected, можно создавать закрытые (для "внешнего мира") члены класса, но вместе с тем они будут наследоваться с возможностью доступа со стороны производных классов.

// Демонстрация использования защищенных членов класса.

usingSystem;

class В {

protectedint i, j; // Закрыт внутри класса В,

//но доступен для класса D.

public void set(int a, int b) { i = a;

j = b;

}

public void show() {

Console.WriteLine(i + " " + j) ;

}}

classD : В {

int k; // Закрытыйчлен.

// Класс D получаетдоступ к членам i и j класса В. public void setk() {

k = i * j ;

}

public void showk() { Console.WriteLine(k) ;

}}

classProtectedDemo { public static void Main() { D ob = new D();

ob.set(2, 3); // OK, так как D "видит" В -члены i и j . ob.show(); // OK, так как D "видит" В -члены i и j .

ob.setk(); // OK, так как это часть самого класса D. ob.showk(); // OK, так как это часть самого класса D.

}}

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