1629295403-b876e2087bddebea4bc9666fb2377a02 (846199), страница 55
Текст из файла (страница 55)
Полиморфизм287/ / Выводим с о с т о я н и я с ч е т о вConsole.WriteLine("БалансBankAccountравен{0:С}",ba.Balance);Console.WriteLine("БалансSavingsAccountравен{0:C}",sa.Balance);// Ожидаем п о д т в е р ж д е н и я п о л ь з о в а т е л яConsole.WriteLine("Нажмите <Enter> для"завершения"+программы...");Console.Read();В э т о м случае ф у н к ц и я M a i n ()с о з д а е т о б ъ е к т B a n k A c c o u n t с н а ч а л ь н ы м баланс о м 2 0 0 и с н и м а е т с н е г о 100. З а т е м те же д е й с т в и я в ы п о л н я ю т с я с о б ъ е к т о м Saving's A c c o u n t .
Когда функция M a i n ( )с н и м а е т д е н ь г и с о с ч е т а б а з о в о г о класса, м е т о дB a n k A c c o u n t . W i t h d r a w ( ) с н и м а е т т о л ь к о у к а з а н н у ю с у м м у ( н о н е б о л е е суммы н асчету). Когда же функция M a i n ()s A c c o u n t . W i t h d r a w ()с н и м а е т д е н ь г и с д е п о з и т н о г о с ч е т а , м е т о д Savingс н и м а е т д о п о л н и т е л ь н у ю с у м м у , р а в н у ю 1.50.Обратите внимание, что метод S a v i n g s A c c o u n t . 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 ( ) , а н е р а б о т а е т непосредс т в е н н о с б а л а н с о м . Е с л и э т о в о з м о ж н о — п у с т ь б а з о в ы й к л а с с с а м работает»своими членами-данными.Чем сокрытие лучше проверки флагаНа первый взгляд добавление флага в метод B a n k A c c o u n t .
W i t h d r a w () представл я е т с я б о л е е п р о с т ы м р е ш е н и е м , ч е м п р е д л о ж е н н ы й в а р и а н т с с о к р ы т и е м метода базов о г о к л а с с а . В к о н ц е к о н ц о в , и с п о л ь з о в а н и е ф л а г а п о т р е б о в а л о д о б а в л е н и я всего л и шьчетырех строк.О д н а к о п р о с т о е р е ш е н и е п о р о ж д а е т м а с с у п р о б л е м .
П е р в а я з а к л ю ч а е т с я в том, ч т окласс B a n k A c c o u n t не должен беспокоиться о деталях работы S a v i n g s A c c o u n t . Гов о р я ф о р м а л ь н о , э т о н а р у ш а е т п р и н ц и п и н к а п с у л я ц и и . Б а з о в ы й к л а с с н е д о л ж е н ничегознать о своих потомках.В с е с к а з а н н о е п р и в о д и т к о в т о р о й , б о л е е с л о ж н о й п р о б л е м е . П р е д п о л о ж и м , банки п оочереди вводит новые с ч е т а — например,CheckingAccount,C D A c c o u n t , TBil-l A c c o u n t .
У к а ж д о г о из н и х — с в о и п р а в и л а с н я т и я д е н е г со с ч е т а и к а ж д ы й используе т с в о й с о б с т в е н н ы й ф л а г . П о с л е т р е х - ч е т ы р е х д о б а в л е н и й н о в ы х т и п о в с ч е т о в старьйметод B a n k A c c o u n t . W i t h d r a w ()н а ч и н а е т в ы г л я д е т ь с л и ш к о м с л о ж н ы м . Каждыйновый вид счета приводит, ко все большим изменениям этого метода.Т а к о е р е ш е н и е с о в е р ш е н н о н е п о д х о д и т . К л а с с ы д о л ж н ы о т в е ч а т ь с а м и з а себя.Случайное сокрытие метода базового классаМетод базового класса может оказаться скрытым случайно. Пусть, например, имеетсям е т о д V e h i c l e .
T a k e O f f ( ) , к о т о р ы й н а ч и н а е т д в и ж е н и е т р а н с п о р т н о г о средства. Позж е кто-то м о ж е т р а с ш и р и т ь класс V e h i c l e , с о з д а в к л а с с A i r p l a n e . П о н я т н о , что методT a k e O f f ( ) э т о г о к л а с с а с о в е р ш е н н о н е т о т ж е , ч т о у к л а с с а V e h i c l e . О ч е в и д н о , что э т ос л у ч а й л о ж н о й т о ж д е с т в е н н о с т и — д в а м е т о д а н е и м е ю т н и ч е г о о б щ е г о , к р о м е имени.К счастью, С# в состоянии о б н а р у ж и т ь т а к у ю проблему.288Часть IV. Объектно-ориентированное программирован®С# генерирует зловещего вида предупреждение при компиляции рассматривавшейсяране д е м о н с т р а ц и о н н о й п р о г р а м м ы H i d i n g W i t h d r a w a l .
И з в с е г о д л и н н о г о т е к с т апредупреждения и н т е р е с п р е д с т а в л я е т т о л ь к о н е б о л ь ш а я е г о ч а с т ь , а и м е н н о :1.. . S a v i n g s A c c o u n t . W i t h d r a w ( d e c i m a l ) 'hidesi n h e r i t e d member'...BankAccount.Withdraw(decimal)'.Uset h e newkeywordifh i d i n g wasintended.C# пытается с о о б щ и т ь , что вы написали м е т о д подкласса, к о т о р ы й имеет то же имя,что и метод б а з о в о г о к л а с с а . Д е й с т в и т е л ь н о ли вы х о т и т е и м е н н о э т о г о ?Это всего л и ш ь предупреждение.
Вы м о ж е т е и не реагировать на него, но всеже крайне желательно ознакомиться со всеми предупреждениями, выводимымикомпилятором, и избавиться от них. Предупреждение почти всегда говорито к а к о й - т о м е л о ч и , к о т о р а я м о ж е т п е р е р а с т и в к р у п н ы е н е п р и я т н о с т и , е с л и вовремя о н е й не позаботиться.Неплохо дать указание компилятору С # рассматриватьвсе предупреждения как,ошибки, по крайней мере на этапе отладки. Д л я этого следует воспользоватьсяProjects Properties и п р о к р у т и т ь п а н е л ь Build с т р а н и ц ыErrors and Warnings. У с т а н о в и т е з н а ч е н и е парам е т р а Warning Level р а в н ы м 4, н а и в ы с ш е й в о з м о ж н о й в е л и ч и н е .
К р о м е т о г о ,в п о д р а з д е л е Treat Warnings as Errors в ы б е р и т е ф л а г АLL. П р и э т о м п р и рабокомандой менюсвойств проекта до разделате над программой вы будете вынуждены устранять все предупреждения также, к а к у с т р а н я е т е р е а л ь н ы е о ш и б к и .
Д а ж е е с л и в ы н е б у д е т е з а с т а в л я т ь компилятор считать предупреждения о ш и б к а м и , все р а в н о т щ а т е л ь н о просматривайте в е с ь с п и с о к п р е д у п р е ж д е н и й п о с л е к а ж д о й с б о р к и п р о г р а м м ы .Описатель n e w , у п о м я н у т ы й в п р е д у п р е ж д е н и и и п о к а з а н н ы й в п р и в е д е н н о м д а л е ефрагменте и с х о д н о г о т е к с т а , г о в о р и т к о м п и л я т о р у С # о т о м , ч т о с о к р ы т и е м е т о д а преднамеренное ( т е м с а м ы м п р е д у п р е ж д е н и е у с т р а н я е т с я ) .// ТеперьnewсpublicW i t h d r a w ()decimalникакихпроблемWithdraw(decimalmWithdrawal){// . . .
Никаких иных изменений не требуется . . .}Т а к о е и с п о л ь з о в а н и е к л ю ч е в о г о с л о в а n e w н е и м е е т н и ч е г о о б щ е г о с е г о применением для создания объекта.Вызов методов базового классаВернемсякметодуS a v i n g s A c c o u n t . W i t h d r a w ()издемонстрационнойпрограммы H i d i n g W i t h d r a w a l , р а с с м а т р и в а в ш е й с я р а н е е в э т о й г л а в е . В ы з о в B a n k A c count . W i t h d r a w ( )из этого нового метода осуществляется при п о м о щ и ключевогослова b a s e .Приведенная д а л е е в е р с и я ф у н к ц и и б е з к л ю ч е в о г о с л о в а b a s e р а б о т а т ь н е будет:new p u b l i cdecimalWithdraw (decimalmWithdrawal){decimalmAmountWithdrawnГлава 13.
Полиморфизм=Withdraw(mWithdrawal);289mAmountWithdrawnreturn+=Withdraw(1.5);mAmountWithdrawn;}В э т о м с л у ч а е в о з н и к а е т та же п р о б л е м а , ч т о и в с л е д у ю щ е м ф р а г м е н т е :voidfn(){f n () ;//Вызовфункциейсамойсебя}В ы з о в f п ()из f п ()п р и в о д и т к рекурсивному в ы з о в у ф у н к ц и е й с а м о й себя. Анапаг и ч н о , т а к о й в ы з о в W i t h d r a w ( ) , к а к п о к а з а н о в ф р а г м е н т е в ы ш е , п р и в о д и т к вызов;функцией самой себя, пока программа в конечном счете не завершится аварийно.Требуется указать С#, что в методеSavingsAccount .Withdraw()следуетщз в а т ь м е т о д B a n k A c c o u n t . W i t h d r a w ( ) .
О д и н и з в а р и а н т о в р е ш е н и я поставлена!задачи состоит в преобразовании указателя t h i s в указатель на объект ВапкАссоияперед выполнением вызова://Withdraw-//базовогоклассаpublicdecimalnewэтаверсияобращаетсяпосредствомксокрытомуявногоWithdraw(decimalметодупреобразованияthismWithdrawal){////ПреобразованиеBankAccount//указателяthisвобъектклассаBankAccountВызовba=decimalсиспользованиемmAmountWithdrawnmAmountWithdrawnreturn(BankAccount)this;Withdraw()+==объектаBankAccountba.Withdraw(mWithdrawal);ba.Withdraw(1.5);mAmountWithdrawn;}Данное решение вполне работоспособно:вызов ba . W i t h d r a w ()в ы з ы в а е т метик л а с с а B a n k A c c o u n t . О д н а к о в б у д у щ е м и з м е н е н и е п р о г р а м м ы м о ж е т привести к лк о м у и з м е н е н и ю и е р а р х и и к л а с с о в , ч т о 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 .
П о д о б н а я м о д и ф и к а ц и я п р и в е д е т к н е в е р н о й р а б о т е функцщнайти причину которой будет нелегко.Н е о б х о д и м с п о с о б п о я с н и т ь С # , ч т о т р е б у е т с я в ы з в а т ь ф у н к ц и ю W i t h d r a w () из класса, я в л я ю щ е г о с я н е п о с р е д с т в е н н ы м п р е д ш е с т в е н н и к о м т е к у щ е г о — п р и ч е м без явнойи м е н о в а н и я э т о г о класса. Д л я э т о й ц е л и в С # с л у ж и т к л ю ч е в о е с л о в о b a s e .Э т о т о ж е к л ю ч е в о е с л о в о b a s e , к о т о р о е к о н с т р у к т о р и с п о л ь з у е т д л я переда!аргумента конструктору базового класса.К л ю ч е в о е с л о в о С# b a s e в п о к а з а н н о м д а л е е ф р а г м е н т е к о д а п р е д с т а в л я е т собой тож е , ч т о и t h i s , н о п р и в е д е н и е к б а з о в о м у к л а с с у в ы п о л н я е т с я н е з а в и с и м о о т того, капименно класс является таковым.//Withdraw//возвращаетnewpublic-можносниматьснятуюdecimalсолюбуюсчетасуммувпределахбаланса;суммуWithdraw(decimalmWithdrawal){//Снятиедополнительнойсуммы1.50base.Withdraw(1.5M);290Часть IV.