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

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

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

Добавлен: 11.12.2025

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

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

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

{

i f b a i s S a v i n g s A c c o u n t

{

S a v i n g s A c c o u n t s a = ( S a v i n g s A c c o u n t ) b a , • s a . W i t h d r a w ( m A m o u n t ) ;

}e l s e

{

b a . W i t h d r a w ( m A m o u n t ) ;

}

}

Теперь, когда M a i n () передает функции объект типа S a v i n g s A c c o u n t , функции M a k e A W i t h d r a w a l () проверяет тип времени выполнения объекта ba и вызывает функцию S a v i n g s A c c o u n t . W i t h d r a w ( ) .

Программист может выполнить вызов одной строкой: ( ( S a v i n g s A c c o u n t ) b a ) . W i t h d r a w ( m A m o u n t ) ;

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

Подход с использованием i s вполне работоспособен, но это далеко не лучшая идея Применение is требует от функции M a k e A W i t h d r a w a l () осведомленности о всех возможных типах счетов, которые имеются (и могут появиться в дальнейшем) в банк Это накладывает на функцию M a k e A W i t h d r a w a l () слишком большую ответстве ность. Да, сейчас ваше приложение обходится двумя классами, но завтра от вас могу потребовать реализовать новый вид счета, например, C h e c k i n g A c c o u n t , и вы будете вынуждены перерыть всю программу в поисках мест, в которые надо внести добавления связанные с проверкой типа аргумента функции в процессе выполнения программы.

Объявление метода виртуальным

В качестве автора функции M a k e A W i t h d r a w a l () вы бы, конечно, не хотели делав ее осведомленной о всех возможных типах счетов. Хотелось бы предоставить это про­ граммисту, использующему функцию M a k e A W i t h d r a w a l ( ) , т.е. заставить С# самому; принимать решение о том, какой метод должен быть вызван,

основываясь на информации о типе объекта времени выполнения программы.

М о ж н о заставить С# самостоятельно принимать решение о версии W i t h d r a w () торую следует вызвать. Для этого необходимо пометить функцию базового класса при п о м о щ и ключевого слова v i r t u a l , а каждую версию функции в подклассах — ключе вым словом o v e r r i d e .

Предыдущая демонстрационная программа переписана с использован полиморфизма, при этом в каждый из методов W i t h d r a w () добавлен вод строки, чтобы было точно видно, какого класса метод вызывается в или ином случае.

/ / P o l y m o r p h i c l n h e r i t a n c e - п о л и м о р ф н о е с о к р ы т и е м е т о д а / / б а з о в о г о к л а с с а

294

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


using S y s t e m ;

 

 

 

namespace

P o l y m o r p h i c l n h e r i t a n c e

 

{

 

 

 

 

/ / B a n k A c c o u n t - п р о с т е й ш и й б а н к о в с к и й с ч е т

 

p u b l i c

c l a s s B a n k A c c o u n t

 

 

 

{

 

 

 

 

p r o t e c t e d d e c i m a l m B a l a n c e ;

 

 

p u b l i c

B a n k A c c o u n t ( d e c i m a l

m l n i t i a l B a l a n c e )

 

m B a l a n c e = m l n i t i a l B a l a n c e ;

 

p u b l i c

d e c i m a l B a l a n c e

 

 

 

g e t { r e t u r n m B a l a n c e ;

}

 

 

p u b l i c v i r t u a l d e c i m a l W i t h d r a w ( d e c i m a l m A m o u n t )

C o n s o l e . W r i t e L i n e ( " B a n k A c c o u n t . W i t h d r a w ( ) с

$ { o } . . . " ,

 

m A m o u n t ) ;

 

d e c i m a l m A m o u n t T o W i t h d r a w = m A m o u n t ;

 

i f ( m A m o u n t T o W i t h d r a w > B a l a n c e )

 

{

 

 

 

 

m A m o u n t T o W i t h d r a w = B a l a n c e ;

 

}

 

 

 

 

m B a l a n c e - = m A m o u n t T o W i t h d r a w ;

 

r e t u r n m A m o u n t T o W i t h d r a w ;

 

 

/ / S a v i n g s A c c o u n t - б а н к о в с к и й с ч е т с н а ч и с л е н и е м

 

// п р о ц е н т о в

 

 

 

p u b l i c c l a s s S a v i n g s A c c o u n t

:

B a n k A c c o u n t

 

{

 

 

 

 

p u b l i c d e c i m a l m l n t e r e s t R a t e ;

 

/ / S a v i n g s A c c o u n t - п р о ц е н т н а я с т а в к а у к а з ы в а е т с я к а к

/ / ч и с л о о т 0 д о 1 0 0

 

 

 

p u b l i c

S a v i n g s A c c o u n t ( d e c i m a l m l n i t i a l B a l a n c e ,

 

 

d e c i m a l m l n t e r e s t R a t e )

 

 

: b a s e ( m l n i t i a l B a l a n c e )

 

{

t h i s . m l n t e r e s t R a t e = m l n t e r e s t R a t e / 1 0 0 ;

/ / A c c u m u l a t e l n t e r e s t - н а ч и с л е н и е п р о ц е н т о в p u b l i c v o i d A c c u m u l a t e l n t e r e s t ( )

{

m B a l a n c e = B a l a n c e + ( B a l a n c e * m l n t e r e s t R a t e ) , -

/ / W i t h d r a w . - с н я т и е с о с ч е т а п р о и з в о л ь н о й с у м м ы , н е

Глава 13. Полиморфизм

295


/ /

п р е в ы ш а ю щ е й и м е ю щ е й с я н а с ч е т у ; в о з в р а щ а е т с н я т у ю

/ /

с у м м у

o v e r r i d e p u b l i c d e c i m a l W i t h d r a w ( d e c i m a l m W i t h d r a w a l )

{

C o n s o l e . W r i t e L i n e ( " S a v i n g s A c c o u n t . W i t h d r a w ( ) . . . " ) ;

C o n s o l e . W r i t e L i n e ( " В ы з о в ф у н к ц и и W i t h d r a w б а з о в о г о " +

 

 

 

 

" к л а с с а

д в а ж д ы . . . ' " ) ;

 

 

/ / С н я т и е 1 . 5 0

 

 

 

 

 

 

b a s e . W i t h d r a w ( 1 . 5 М ) ;

 

 

 

 

/ / С н я т и е в п р е д е л а х о с т а в ш е й с я с у м м ы

 

 

r e t u r n b a s e . W i t h d r a w ( m W i t h d r a w a l ) ;

 

 

}

 

 

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

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 k e A W i t h d r a w a l ( B a n k A c c o u n t

b a ,

 

 

 

 

 

 

d e c i m a l m A m o u n t )

{

 

 

 

 

 

 

 

 

b a . W i t h d r a w ( m A m o u n t ) ;

 

 

 

 

}

 

 

 

 

 

 

 

 

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 )

 

 

B a n k A c c o u n t

b a ;

 

 

 

 

 

 

S a v i n g s A c c o u n t

s a ;

 

 

 

 

 

/ / В ы в о д б а л а н с а

 

 

 

 

 

C o n s o l e . W r i t e L i n e ( " M a k e A W i t h d r a w a l ( b a ,

. . . ) " ) ;

ba = n e w B a n k A c c o u n t ( 2 0 0 M ) ;;

 

 

 

M a k e A W i t h d r a w a l ( b a ,

1 0 0 M ) ;

 

 

 

 

C o n s o l e . W r i t e L i n e ( " Б а л а н с B a n k A c c o u n t р а в е н

{ 0 : C } " ,

 

 

 

 

b a . B a l a n c e ) ;

 

 

 

C o n s o l e . W r i t e L i n e ( " M a k e A W i t h d r a w a l ( s a ,

. . . ) " ) ;

s a = n e w S a v i n g s A c c o u n t ( 2 0 0 M ,

1 2 ) ;

 

 

M a k e A W i t h d r a w a l ( s a ,

1 0 0 M ) ;

 

 

 

 

C o n s o l e . W r i t e L i n e ( " Б а л а н с

S a v i n g s A c c o u n t

р а в е н { 0 : C } " ,

 

 

 

 

s a . B a l a n c e ) ;

 

 

 

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

 

 

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 ( ) ;

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

} }

 

 

 

 

 

 

 

 

Вывод программы имеет следующий вид:

 

 

 

 

M a k e A W i t h d r a w a l ( b a ,

. . . )

 

 

 

 

 

B a n k A c c o u n t . W i t h d r a w ( )

с

$ 1 0 0 . . .

 

 

 

 

Б а л а н с B a n k A c c o u n t р а в е н $ 1 0 0 . 0 0

 

 

 

 

M a k e A W i t h d r a w a l ( s a ,

. . . )

 

 

 

 

 

S a v i n g s A c c o u n t . W i t h d r a w ( ) . . .

 

 

 

 

296

 

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


Вызов ф у н к ц и и W i t h d r a w

б а з о в о г о

к л а с с а д в а ж д ы . . .

B a n k A c c o u n t . W i t h d r a w ( )

с

$ 1 . 5 . . .

B a n k A c c o u n t . W i t h d r a w ( )

с $ 1 0 0 . . .

Баланс

S a v i n g s A c c o u n t

р а в е н $ 9 8 . 5 0

Нажмите

< E n t e r >

д л я з а в е р ш е н и я

п р о г р а м м ы . . .

Метод W i t h d r a w ()

помечен в

базовом

классе B a n k A c c o u n t как v i r t u a l , в то вре­

мя как в подклассе он помечен как o v e r r i d e . Метод M a k e A W i t h d r a w a l () остается без изменений, и вывод при его вызове различен из-за того, что разрешение вызова ba. W i t h d r a w () осуществляется на основании типа ba во время выполнения программы.

Для полного понимания того, как это работает, желательно пошагово пройти программу в отладчике Visual Studio 2005. Для этого соберите программу как обычно, а затем нажимайте клавишу <F11> для пошагового ее выполнения. Это достаточно впечатляющее зрелище, когда один и тот же вызов приводит в раз­ ные моменты к двум разным методам.

Будьте экономны при объявлении методов виртуальными. Все имеет свою це­ ну, так что используйте ключевое слово v i r t u a l только при необходимости.

Утка — вид птицы. Так же как воробей или колибри. Любая птица представляет ка­ кой-то подвид птиц. Но обратная сторона медали в том, что нет птицы, которая была бы птицей вообще. С точки зрения программирования это означает, что все объекты B i r d являются экземплярами каких-то подклассов B i r d , но не имеется ни одного экземпляра класса B i r d . Так что же такое птица? Это всегда какой-то конкретный вид — пингвин, курица или, к примеру, страус.

Различные типы птиц имеют множество общих свойств (в противном случае они бы не были птицами), но нет двух типов, у которых бы общими были все свойства. Если бы такие типы были, они были бы одинаковыми типами, ничем не отличающимися друг от друга.

Разложение классов

Люди систематизируют объекты, выделяя их общие черты. Ч т о б ы увидеть, как это работает, рассмотрим два к л а с с а — H i g h S c h o o l и U n i v e r s i t y , показанные на рис. 13.1. Здесь для описания классов использован Унифицированный Я з ы к Моделиро­ вания (Unified Modeling Language, U M L ) , графический язык, описывающий классы и их взаимоотношения друг с другом.

Помните — машина ЯВЛЯЕТСЯ транспортным средством, но С О Д Е Р Ж И Т мотор.

t Как видно на рис. 13.1, у ш к о л ы и университета много общих свойств. И у школы, и у университета имеется открытый метод E n r o l l () для добавления объекта S t u d e n t (зачисления в учебное заведение). Оба класса имеют закрытый член n u m S t u d e n t s , в котором хранится число учащихся. Еще одно общее свойство — взаимоотношения уча­ щихся и учебных заведений: в учебном заведении может быть много учащихся, в то время

Глава 13. Полиморфизм

297


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

Рис. 13.1. UML-описание классов HighSchool и University

В дополнение к свойствам ш к о л ы университет содержит метод G e t G r a n t () и членданные nAvgSAT .

Рис. 13.1 корректно отображает ситуацию, но большая часть информации дублирует­ ся. Уменьшить дублирование можно, если позволить классу U n i v e r s i t y унаследовать более простой класс H i g h S c h o o l , как показано на рис. 13.2.

 

Рис.

13.2.

Наследование

класса

 

 

 

HighSchool

упрощает

класс

Uni -

 

 

 

versity,

но

привносит

определен­

 

 

 

ные проблемы

 

 

 

 

 

 

Класс

H i g h S c h o o l остается

неизменным,

но

класс

U n i v e r s i t y

при этом

проще

описать.

М о ж н о сказать, что U n i v e r s i t y — это

класс

H i g h S c h o o l

с членом

nAvg-

SAT и методом G e t G r a n t ( ) . Однако такое решение имеет одну фундаментальную про­ блему — университет вовсе не школа со специальными свойствами.

Вы можете сказать: " Н у и что? Главное, что наследование работает и экономит наши усилия". Да, конечно, это так, но сказанное выше — не просто стилистическая тривиаль­ ность. Такое неверное представление может ввести в заблуждение программиста как сейчас, так и в будущем. В один прекрасный день ему, незнакомому с вашими фокусами, придется читать и разбираться в ваших исходных текстах, и такое неверное представле­

ние может привести к неправильному пониманию программы .

 

Кром е того, неверное представление м о ж е т привести к

р е а л ь н ы м проблемам.

П р е д п о л о ж и м , что в ш к о л е р е ш и л и выбирать лучшего ученика,

и для этого програм-

298

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