Г. Шилдт - Полный справочник по C# (1160789), страница 36
Текст из файла (страница 36)
Подробнее о методах и классах183// Метод возвращает значение true, если стек пуст,public bool empty() {return tos==0;// Возвращает общий объем стека,public int capacity() {return stck.Length;// Возвращает текущее количество объектов в стеке,public int getNum() {return tos;|Рассмотрим класс Stack подробнее.
Его объявление начинается с объявления двухпеременных экземпляров:c h a r [ ] s t c k ; // Массив для хранения данных стека,int tos;// Индекс вершины стека.Массив s t c k обеспечивает хранение данных стека, которыми в нашем случае являются символы. Обратите внимание на то, что память для массива здесь не выделяется.
Это делается в конструкторе класса stack. Член t o s содержит индекс вершиныстека.Оба члена s t c k и t o s по умолчанию объявлены закрытыми, и именно этот фактпозволяет обеспечить функционирование механизма "первым вошел — последнимвышел". Если бы к массиву s t c k был разрешен открытый доступ, то к элементам стека можно было бы обращаться совершенно беспорядочно. Кроме того, посколькучлен t o s содержит индекс "верхнего" элемента стека, чтобы избежать искажения стека, необходимо предотвратить манипуляции над этим членом вне класса stack. Доступ пользователя к членам s t c k и t o s должен быть организован косвенным образом,посредством специальных открытых методов.Вот как выглядит конструктор стека:// Создаем пустой класс Stack заданного размера,public Stack(int size) {stck = new char[size]; // Выделяем память для стека.tos = 0;}Этому конструктору передается необходимый размер стека.
Поэтому он выделяетсоответствующую область памяти для массива и устанавливает переменную экземпляра t o s равной нулю. Таким образом, нулевое значение переменной t o s служит признаком того, что стек пуст.Открытый метод push () помещает в стек один элемент. Вот определение этогометода:// Помещаем символы в стек,public void push(char ch) {if(tos==stck.Length) {Console.WriteLine(" - Стек заполнен.");return;stck[tos] = ch;tos++;184Часть I. Язык С #Элемент, помещаемый в стек, передается в качестве параметра ch. Прежде чемэлемент будет добавлен в стек, выполняется проверка, хватит ли в массиве места, чтобы принять очередной элемент.
Для выполнения этой проверки достаточно убедитьсяв том, что значение переменной t o s не превышает длину массива s t c k . Если ещеесть свободное место, элемент сохраняется в массиве s t c k по индексу, заданномузначением переменной t o s , после чего значение t o s инкрементируется. Таким образом, переменная t o s всегда содержит индекс следующего свободного элемента в массиве s t c k .Чтобы удалить элемент из стека, необходимо вызвать метод pop ().
Вот его определение:// Извлекаем символ из стека,public char pop() {if(tos==0) {Console.WriteLine(" - Стек пуст.");return (char) 0;tos — ;return stckftos];}И здесь проверяется значение переменной t o s . Если оно равно нулю, значит, стекпуст. В противном случае значение t o s декрементируется, и по полученному индексувозвращается элемент стека.Несмотря на то что push () и pop () — единственные, жизненно необходимые дляреализации стека методы, существуют и другие действия, которые были бы полезныдля его функционирования, поэтому в классе s t a c k реализовано еще четыре метода( f u l l ( ) , empty ( ) , c a p a c i t y () и getNumO). Эти методы предоставляют информацию о состоянии стека.
Приведем их определения.// Метод возвращает значение true, если стек полон,public bool full() {return tos==stck.Length;}// Метод возвращает значение true, если стек пуст,public bool empty() {return tos==0;}'// Возвращает общий объем стека,,public int capacity() {return stck.Length;}// Возвращает текущее количество объектов в стеке.public int getNumO {return tos;}Метод f u l l () возвращает значение t r u e , если стек полон, и значение f a l s e впротивном случае. Метод empty () возвращает значение t r u e , если стек пуст, и значение f a l s e в противном случае.
Чтобы получить общий объем стека (т.е. количествоэлементов, которое он может содержать), достаточно вызвать метод c a p a c i t y ( ) . Ачтобы узнать, сколько элементов хранится в стеке в данный момент, вызовите методgetNumO. Эти методы удобно использовать, поскольку для получения информации,Глава 8. Подробнее о методах и классах185которую они предоставляют, требуется доступ к члену t o s , который закрыт в рамкахкласса Stack.Следующая программа демонстрирует работу стека.// Демонстрация использование класса Stack.using System;class StackDemo {public static voidStack stkl = newStack stk2 = newStack stk3 = newchar ch;int i ;Main() {Stack(lO);Stack(lO);Stack(lO);// Помещаем ряд символов в стек stkl.Console.WriteLine("Помещаем символы от А до Z в стек stkl.");for(i=0; !stkl.full(); i++)stkl.push((char) (fAf + i) ) ;if (stkl.fulK) ) Console.WriteLine ("Стек stkl полон.");// Отображаем содержимое стека stkl.Console.Write("Содержимое стека stkl: " ) ;while( !stkl.empty() ) {ch = stkl.pop();Console.Write(ch);}Console.WriteLine();if(stkl.empty()) Console.WriteLine("Стек stkl пуст.Хп");// Помещаем еще символы в стек stkl.Console.WriteLine("Снова помещаем символы от А до Z в стек stkl.");for(i=0; !stkl.full(); i++)stkl.push((char) (fAf + i));/* Теперь извлекаем элементы из стека stkl и помещаем ихв стек stk2.В результате элементы стека stk2 должны бытьрасположены в обратном порядке.
*/Console.WriteLine("Теперь извлекаем элементы из стека stkl и\п" +" помещаем их в стек stk2.");while( !stkl.empty() ) {ch = stkl.pop();stk2.push(ch) ;}Console.Write("Содержимое стека stk2: ") ;while( !stk2.empty() ) {ch = stk2.pop();Console.Write(ch) ;186Часть I. Язык C#Console.WriteLine("\n");// Помещаем 5 символов в стек stk3.Console.WriteLine("Помещаем 5 символов в стек stk3.");for(i=0; i < 5; i++)stk3.push((char) (fAf + i));Console.WriteLine("Объем стека stk3: " + stk3.capacity());Console.WriteLine("Количество объектов в стеке stk3: " +stk3.getNum());При выполнении этой программы получаем следующие результаты:Помещаем символы от А до Z в стек stkl.Стек stkl полон.Содержимое стека stkl: JIHGFEDCBAСтек stkl пуст.Снова помещаем символы от А до Z в стек stkl.Теперь извлекаем элементы из стека stkl ипомещаем их в стек stk2.Содержимое стека stk2: ABCDEFGHIJПомещаем 5 символов в стек stk3.Объем стека stk3: 10Количество объектов в стеке stk3: 5Передача объектов методамДо сих пор в качестве параметров методов мы использовали значения типа i n tили double.
Наряду с параметрами в виде значений методам можно передавать объекты. Рассмотрим, например, следующую программу:// Демонстрация возможности передачи методам объектов.using System;class MyClass {int alpha, beta;public MyClass(int i, int j) {alpha =' i ;beta = j ;}/* Метод возвращает true, если параметр ob содержитте же значения, что и вызывающий объект. */public bool sameAs(MyClass ob) {if((ob.alpha == alpha) & (ob.beta == beta))return true;else return false;Глава 8. Подробнее о методах и классах187// Создаем копию объекта ob.public void copy(MyClass ob) {alpha = ob.alpha;beta = ob.beta;public void show() {Console.WriteLine("alpha: {0}, beta: {1}",alpha, beta);class PassOb {public static void Main() {MyClass obi = new MyClass(4, 5 ) ;MyClass ob2 = new MyClass(6, 7 ) ;Console.Write("obi: " ) ;obi.show();Console.Write("ob2: " ) ;ob2.show();if(obi.sameAs(ob2))Console.WriteLine("obi и оЬ2 имеют одинаковые значения.");elseConsole.WriteLine("obi и оЬ2 имеют разные значения.");Console.WriteLine();// Теперь делаем объект obi копией объекта оЬ2.obi.copy(оЬ2);Console.Write("obi после копирования: " ) ;obi.show();if(obi.sameAs(ob2))Console.WriteLine("obi и оЬ2 имеют одинаковые значения.");elseConsole.WriteLine("obi и оЬ2 имеют разные значения.");Выполнив эту программу, получаем такие результаты:obi: alpha: 4, beta: 5ob2: alpha: б, beta: 7obi и оЬ2 имеют разные значения.obi после копирования: alpha: б, beta: 7obi и оЬ2 имеют одинаковые значения.Каждый из методов — sameAs () и сору () — принимает в качестве аргумента объект.
Метод sameAs() сравнивает значения alpha и b e t a вызывающего объекта созначениями alpha и b e t a объекта, переданного в качестве аргумента ob. Этот метод188Часть I. Язык С#возвращает значение t r u e только в том случае, если сравниваемые объекты содержатодинаковые значения в соответствующих переменных экземпляров.
Метод сору()присваивает значения alpha и b e t a объекта, переданного в качестве аргумента ob,переменным экземпляра alpha и b e t a вызывающего объекта. Обратите внимание нато, что в обоих случаях в качестве типа параметра указан класс MyClass. Как видноиз этой программы, объекты (имеющие тип класса) передаются методам точно так же,как и значения встроенных типов.Как происходит передача аргументовВ предыдущем примере передача аргументов методу представляла собой простуюзадачу.
Однако существуют некоторые нюансы, которые там не были показаны. В определенных случаях результаты передачи объекта будут отличаться от результатов передачи необъектных аргументов. Чтобы понять причину, необходимо рассмотреть двавозможных способа передачи аргументов.Первый способ называется вызовом по значению (call-by-value). В этом случае значение аргумента копируется в формальный параметр метода.
Следовательно, изменения, внесенные в параметр метода, не влияют на аргумент, используемый при вызове.Второй способ передачи аргумента называется вызовом по ссылке (call-by-reference).Здесь для получения доступа к реальному аргументу, заданному при вызове, используется ссылка на аргумент. Это значит, что изменения, внесенные в параметр, окажутвоздействие на аргумент, использованный при вызове метода.При передаче методу значения нессылочного типа (например, i n t или double)имеет место вызов по значению.
Таким образом, то, что происходит с параметром,который получает аргумент, никак не влияет на данные вне метода. Рассмотрим следующую программу:// Демонстрация передачи простых типов по значению.u s i n g System;class Test {/* Этот метод не оказывает влияния на аргументы,используемые в его вызове. */public void noChange(int i, int j) {i = i + j;jj = -j;class CallByValue {public static void Main() {Test ob = new Test();inta = 15, b = 20;Console.WriteLine("а и b перед вызовом: " +a + " " + b) ;ob.noChange(a, b ) ;Console.WriteLine("а и b после вызова: " +a + " " + b) ;Глава 8. Подробнее о методах и классах189Результаты выполнения этой программы выглядят так:I а и b перед вызовом: 15 20I а и b после вызова: 15 20Как видите, операции, которые выполняются внутри метода noChange ( ) , невлияют на значения а и Ь, используемые при вызове метода.При передаче методу ссылки на объект ситуация несколько усложняется.