ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 11.12.2025

Просмотров: 3141

Скачиваний: 1

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
/ / Т е п е р ь ф у н к ц и я / / п р и н а д л е ж и т к л а с с у
/ / S t u d e n t

s t r i n g

sName)

{

 

s t u d e n t . s N a m e = s N a m e ;

 

}

 

}

 

p u b l i c c l a s s P r o g r a m

 

{

 

p u b l i c s t a t i c v o i d M a i n ( s t r i n g [ ]

a r g s )

{

S t u d e n t s t u d e n t = n e w S t u d e n t ( ) ;

/ / П р и с в а и в а е м и м я н е п о с р е д с т в е н н ы м о б р а щ е н и е м к / / о б ъ е к т у -

C o n s o l e . W r i t e L i n e ( " С н а ч а л а : " ) ; s t u d e n t . s N a m e = " M a d e l e i n e " ;

S t u d e n t . O u t p u t N a m e ( s t u d e n t ) ;

/ / И з м е н я е м и м я с п о м о щ ь ю ф у н к ц и и

C o n s o l e . W r i t e L i n e ( " П о с л е

и з м е н е н и я : " ) ;

S t u d e n t . S e t N a m e ( s t u d e n t , " W i l l a " ) ;

S t u d e n t . O u t p u t N a m e ( s t u d e n t ) ;

/ / О ж и д а е м п о д т в е р ж д е н и я

п о л ь з о в а т е л я

C o n s o l e . W r i t e L i n e ( " Н а ж м и т е < E n t e r > д л я " +

" з а в е р ш е н и я п р о г р а м м ы . . . " ) ;

C o n s o l e . R e a d ( ) ;

}

}

По сравнению с программой P a s s O b j e c t данная программа имеет только одно важщ| изменение: функции O u t p u t N a m e () и S e t N a m e () перенесены в класс S t u d e n t .

Из-за этого изменения функция M a i n () вынуждена обращаться к означенным фущ| циям с указанием класса S t u d e n t . Эти функции теперь являются членами класса Stu-| d e n t , а не P r o g r a m , которому принадлежит функция M a i n ()

Это маленький, но достаточно важный шаг. Размещение функции OutputName! в классе приводит к повышению степени повторного использования: внешние функц которым требуется выполнить вывод объекта на экран, могут найти функцию Output Name () вместе с другими функциями в классе, следовательно, писать такие функ для каждой программы, применяющей класс S t u d e n t , не требуется.

Указанное решение лучше и с философской точки зрения. Класс P r o g r a m не доля беспокоиться о том, как инициализировать имя объекта S t u d e n t , или о том, как выпо: нить вывод его имени на экран. Всю эту информацию должен содержать сам класс Stu d e n t . Объекты отвечают сами за себя.

В действительности функция M a i n () не должна инициализировать объем именем Madeleine непосредственно — в этом случае также следует использ< вать функцию S e t N a m e ( ) .

180

Часть III. Объектно-основанное программирована


Внутри самого класса S t u d e n t одна функция-член может вызывать другую без яв­ ного указания имени класса. Функция S e t N a m e () может вызвать функцию O u t p u t - feme (), не указывая имени класса. Если имя класса не указано, С# считает, что вызвана функция из того же класса.

Определение метода

Обращение к членам данных объекта — экземпляра класса — выполняется посредст­

вом указания объекта, а не класса:

 

 

 

 

Student

s t u d e n t

=

n e w S t u d e n t ( ) ;

/ /

С о з д а н и е

э к з е м п л я р а S t u d e n t

student . sName

=

" M a d e l e i n e " ;

/ /

О б р а щ е н и е

к ч л е н у

C# позволяет вызывать нестатические

функции-члены аналогично:

student. S e t N a m e ( " M a d e l e i n e " )

;

 

 

 

 

Следующий пример демонстрирует это:

 

/ / I n v o k e M e t h o d - в ы з о в ф у н к ц и и - ч л е н а с у к а з а н и е м о б ъ е к т а

using S y s t e m ;

 

 

 

 

 

 

namespace

I n v o k e M e t h o d

 

 

 

 

{

 

 

 

 

 

 

 

 

class

S t u d e n t

 

 

 

 

 

 

{

 

 

 

 

 

 

 

 

/ / И н ф о р м а ц и я о б и м е н и с т у д е н т а

 

 

p u b l i c

s t r i n g

s F i r s t N a m e ;

 

 

 

p u b l i c

s t r i n g

s L a s t N a m e ;

 

 

 

 

/ / S e t N a m e - с о х р а н е н и е и н ф о р м а ц и и о б и м е н и

p u b l i c v o i d S e t N a m e ( s t r i n g s F N a m e , s t r i n g s L N a m e )

{

s F i r s t N a m e = s F N a m e ; s L a s t N a m e = s L N a m e ;

}

/ /

T o N a m e S t r i n g - п р е о б р а з у е т о б ъ е к т к л а с с а S t u d e

/ /

с т р о к у д л я в ы в о д а

p u b l i c s t r i n g T o N a m e S t r i n g ( )

{

s t r i n g s = s F i r s t N a m e + " " + s L a s t N a m e ; return s;

}

}

public

c l a s s P r o g r a m

 

{

 

 

p u b l i c

s t a t i c v o i d M a i n ( )

 

{

 

 

S t u d e n t s t u d e n t = n e w S t u d e n t ( ) ;

s t u d e n t . S e t N a m e ( " S t e p h e n " ,

" D a v i s " ) ;

Глава 8. Методы класса

181


C o n s o l e . W r i t e L i n e ( " И м я с т у д е н т а "

+s t u d e n t . T o N a m e S t r i n g ( ) ) ;

/ / О ж и д а е м п о д т в е р ж д е н и я п о л ь з о в а т е л я

C o n s o l e . W r i t e L i n e ( " Н а ж м и т е < E n t e r > д л я " +

" з а в е р ш е н и я п р о г р а м м ы . . . ") ;

C o n s o l e . R e a d ( ) ;

}

}

}

Вывод данной программы состоит из одной строки: Имя с т у д е н т а S t e p h e n D a v i s

Эта программа очень похожа на программу P a s s O b j e c t T o M e m b e r F u n c t i o n . B в веденной версии используются нестатические функции для работы с именем и фамилией, Программа начинает с создания нового объекта s t u d e n t класса S t u d e n t , после го вызывает функцию S e t N a m e ( ) , которая сохраняет строки " S t e p h e n " и "Davi

в членах-данных s F i r s t N a m e и s L a s t N a m e . И наконец, программа вызывает с цию-член T o N a m e S t r i n g ( ) , возвращающую имя студента, составленное из двух а По историческим причинам, никак не связанным с С#, нестатические функц члены называются методами. В книге будет использоваться термин метод] нестатических функций-членов, и термин функция — для функций всех про типов. Некоторые программисты применяют термины метод экземп

(нестатический) и метод класса (статический).

Вернемся вновь к методу S e t N a m e ( ) , предназначенному для изменения значений лей объекта класса S t u d e n t . Какой именно объект модифицирует метод SetName! Рассмотрим, как работает следующий пример:

S t u d e n t c h r i s t a = n e w S t u d e n t ( ) ;

/ / С о з д а е м д в у х с о в е р ш е н н о

S t u d e n t s a r a h

= n e w S t u d e n t ( ) ;

/ / р а з н ы х с т у д е н т о в

c h r i s t a . S e t N a m e ( " C h r i s t a " ,

" S m i t h " ) ;

s a r a h . S e t N a m e ( " S a r a h " ,

" J o n e s " ) ;

 

Первый вызов S e t N a m e () изменяет поля объекта c h r i s t a , а второй — объект s a r a h . е

Программисты на С# говорят, что метод работает с текущим объектом. В пер вом вызове текущим объектом является c h r i s t a , во втором — s a r a h .

Полное имя метода

Имеется тонкая, но важная проблема, связанная с описанием имен методов. Рассмот рим следующий фрагмент исходного текста:

p u b l i c

c l a s s

P e r s o n

{

 

 

p u b l i c

v o i d A d d r e s s ( )

{

 

C o n s o l e . W r i t e L i n e ( " H i " ) ;

182

Часть III. Объектно-основанное программном


public c l a s s L e t t e r

(

s t r i n g s A d d r e s s ;

/ / С о х р а н е н и е а д р е с а

p u b l i c v o i d A d d r e s s ( s t r i n g s N e w A d d r e s s )

}

sAddress = sNewAddress;

}

}

Любое обсуждение метода A d d r e s s () после этого становится неоднозначным. Ме­ тод A d d r e s s () класса P e r s o n не имеет ничего общего с методом A d d r e s s () класса Letter. Если кто-то скажет, что в этом месте нужен вызов метода A d d r e s s ( ) , то ка­ кой именно метод A d d r e s s () имеется в виду?

Проблема не в самих методах, а в описании. Метод A d d r e s s () как независимая са­

модостаточная сущность просто не существует— существуют методы

Р е г -

son. A d d r e s s () и L e t t e r . A d d r e s s ( ) . Путем добавления имени класса в

начало

имени метода явно указывается, какой именно метод имеется в виду.

 

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

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

Таким образом, A d d r e s s () можно рассматривать как имя метода, а его класс — как фамилию.

Рассмотрим следующий метод S t u d e n t . S e t N a m e ( ) : class S t u d e n t

/ /

И н ф о р м а ц и я о б и м е н и с т у д е н т а

p u b l i c

s t r i n g s F i r s t N a m e ;

p u b l i c

s t r i n g s L a s t N a m e ;

/ /

S e t N a m e - с о х р а н е н и е и н ф о р м а ц и и о б и м е н и

p u b l i c v o i d S e t N a m e ( s t r i n g s F N a m e ,

s t r i n g s L N a m e )

{

 

s F i r s t N a m e = s F N a m e ;

 

s L a s t N a m e = s L N a m e ;

 

}

 

}

 

public class Program

 

{

183

Шва 8. Методы класса

public static void Main()

 


{

S t u d e n t

s t u d e n t l

= n e w S t u d e n t ( ) ;

s t u d e n t l . S e t N a m e ( " J o s e p h " ,

" S m i t h " ) ;

S t u d e n t

s t u d e n t 2

= n e w S t u d e n t ( ) ;

s t u d e n t 2 . S e t N a m e ( " J o h n " ,

" D a v i s " ) ;

}

}

Функция M a i n () использует метод S e t N a m e () для того, чтобы обновить поляом ектов s t u d e n t l и s t u d e n t 2 . Но внутри метода S e t N a m e () нет ссылки ни на какя объект типа S t u d e n t . Как уже было выяснено, метод работает "с текущим объектов Но как он знает, какой именно объект — текущий?

Ответ прост. Текущий объект передается при вызове метода как неявный аргумент-I например, вызов

s t u d e n t l . S e t N a m e ( " J o s e p h " ,

" S m i t h " ) ;

 

эквивалентен следующему:

 

 

S t u d e n t . S e t N a m e ( s t u d e n t l ,

" J o s e p h " ,

" S m i t h " ) ;

/ /

Э т о - э к в и в а л е н т н ы й в ы з о в ( о д н а к о э т о т в ы з о в н е б у д е т

/ /

к о р р е к т н о с к о м п и л и р о в а н )

 

Я не хочу сказать, что вы можете вызвать метод S e t N a m e () двумя различными сп

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

идругие аргументы. Оставьте эту задачу компилятору.

Ачто можно сказать о вызове одного метода из другого? Этот вопрос иллюстриру ся следующим фрагментом исходного текста:

p u b l i c

c l a s s

S t u d e n t

 

{

 

 

 

 

p u b l i c

s t r i n g

s F i r s t N a m e , -

 

p u b l i c

s t r i n g

s L a s t N a m e ;

 

p u b l i c

v o i d

S e t N a m e ( s t r i n g s F i r s t N a m e , s t r i n g s L a s t N a m e )

S e t F i r s t N a m e ( s F i r s t N a m e ) ;

 

S e t L a s t N a m e ( s L a s t N a m e ) ;

 

p u b l i c

v o i d

S e t F i r s t N a m e ( s t r i n g

s N a m e )

s F i r s t N a m e = s N a m e ;

 

p u b l i c

v o i d

S e t L a s t N a m e ( s t r i n g

s N a m e )

s L a s t N a m e = s N a m e ;

 

}

В вызове S e t F i r s t N a m e () не видно никаких объектов. Дело в том, что при вызок| одного метода объекта из другого в качестве неявного текущего объекта передается ти же объект, что и для вызывающего метода. Обращение к любому члену в методе объем рассматривается как обращение к текущему объекту, так что метод знает сам, каком именно объекту он принадлежит.

184

Часть III. Объектно-основанное программирование]