1629295403-b876e2087bddebea4bc9666fb2377a02 (846199), страница 28
Текст из файла (страница 28)
0 ) ;// Ожидаем подтверждения пользователяC o n s o l e . W r i t e L i n e ( " Н а ж м и т е < E n t e r > для " +"завершения программы. . . " ) ;Console.Read();}// A v e r a g e A n d D i s p l a y - усредняет два числа и выводит// результат с использованием переданных метокpublic s t a t i cvoid AverageAndDisplay(string si,double dl,s t r i n g s2,d o u b l e d2){double dAverage = (dl + d2) / 2 ;Console.WriteLine("Среднее "+ si+ ", равной " + dl+ ", и "+ s2+ ", равной " + d2+ ", равно "+ dAverage);Вот как выглядит вывод этой программы на экран:Среднее оценки 1 , равной 3 .
5 , и оценки 2 , равной 4 ,Нажмите < E n t e r > для завершения программы. . .равно 3 . 7 5Функция A v e r a g e A n d D i s p l a y () объявлена с несколькими аргументами в том порядке, в котором они в нее передаются.Как обычно, выполнение программы начинается с первой команды после M a i n ( ) .Первая строка после M a i n ( ) , не являющаяся комментарием, вызывает функцию A v e r a g e A n d D i s p l a y ( ) , передавая ей две строки и два значения типа d o u b l e .Функция A v e r a g e A n d D i s p l a y ()вычисляет среднее переданных значений типаdouble, dl и d 2 , переданных в функцию вместе с их именами (содержащимися в переменных si и s 2 ) , и сохраняет полученное значение в переменной d A v e r a g e .Изменение значений аргументов внутри функции может привести к ошибкам.Разумнее присвоить эти значения временным переменным и модифицироватьуже их.Глава 7. Функции функций151Соответствие определений аргументов их использованиюКаждый аргумент в вызове функции должен соответствовать определенафункции как в смысле типа, так и в смысле порядка.
Приведенный далее шходный текст некорректен и вызывает ошибку в процессе компиляции.// A v e r a g e W i t h C o m p i l e r E r r o rusingSystem;namespace-этаверсиянекомпилируется!Example{publicclassProgram{publicstaticvoidMain(string[]args){// Обращение к ф у н к ц и и - ч л е н уAverageAndDisplay("оценки 1","оценки2",3.5,4.0);// Ожидаем п о д т в е р ж д е н и я п о л ь з о в а т е л яConsole.WriteLine("Нажмите <Enter> для " +" з а в е р ш е н и я п р о г р а м м ы . .
. ") ;Console.Read();}// A v e r a g e A n d D i s p l a y - у с р е д н я е т д в а ч и с л а и выводит// р е з у л ь т а т с и с п о л ь з о в а н и е м переданных метокpublicstaticvoid AverageAndDisplay(string si,double dl,s t r i n g s2,d o u b l e d2){}d o u b l e d A v e r a g e = ( d l + d 2) / 2;Console.WriteLine("Среднее "++ ", р а в н о й " ++ ", и "++ ", р а в н о й " ++ ", р а в н о "+sidls2d2dAverage);}C# обнаруживает несоответствие типов передаваемых функции аргументов с аргументами в определении функции.
Строка " о ц е н к и 1 " соответствует типу s t r i n gопределении функции; однако согласно определению функции вторым аргументадолжно быть число типа d o u b l e , в то время как при вызове вторым аргументом фушции оказывается строка s t r i n g .Это случилось потому, что я просто обменял местами второй и третий аргумент!функции. И это как раз то, за что я не люблю компьютеры — именно за то, что они понимают все совершенно буквально.Чтобы исправить ошибку, достаточно поменять местами второй и третий аргументывызове функции A v e r a g e A n d D i s p l a y ( ) .152Часть III.
Объектно-основанное программированПерегрузка функцииЪ одном к л а с с е м о ж е т б ы т ь д в е ф у н к ц и и с о д н и м и т е м же и м е н е м — приусловииразличияихЭтоаргументов.явлениеназываетсяперегрузкой(overloading) и м е н и ф у н к ц и и .Вот п р и м е р п р о г р а м м ы , д е м о н с т р и р у ю щ е й перегрузку.// A v e r a g e A n d D i s p l a y O v e r l o a d e d - эта версия демонстрирует// возможность перегрузки функции вычисления и вывода// среднего значенияusingSystem;namespaceAverageAndDisplayOverloaded{publicclassProgram{publicstaticvoidMain(string[]args){// Вызов первой функции-членаA v e r a g e A n d D i s p l a y ( " м о е й оценки", 3 . 5 ,"твоей оценки",- 4 .
0 ) ;Console.WriteLine();// Вызов второй функции-членаAverageAndDisplay(3.5,4.0);// Ожидаем подтверждения пользователяConsole.WriteLine("Нажмите<Enter>для"+"завершения программы...");Console.Read();// A v e r a g e A n d D i s p l a y - вычисление среднего значения двух// чисел и вывод его на экран с переданными функции// метками этих чиселpublicvoidstaticAverageAndDisplay(stringstring{double dAverage = (dl + d2) / 2 ;Console.WriteLine("Среднее"si,s2,+doubledoubledl,d2)si+ ", равной " + d l ) ;Console.WriteLine("и"+s2+ ", равной " + d2+ ", равно "}public static void AverageAndDisplay(double dl,+ dAverage);doubled2){doubledAverageГлава 7. Функции функций=(dl+d2)/2;153Console.WriteLine("среднее+ " и "+ " равно""+ dl+ d2+ dAverage);В программе определены две версии функции A v e r a g e A n d D i s p l a y ( ) . Программвызывает одну из них после другой, передавая им соответствующие аргументы.
С# в colстоянии определить по переданным функции аргументам, какую из версий следует ви|звать, сравнивая типы передаваемых значений с определениями функций. Программкорректно компилируется и выполняется, выводя на экран следующие строки:Среднееи твоеймоей оценки, равной 3.5оценки, равной 4, равноСреднееНажмите3.5 и 4<Enter>равно 3.75для завершения3.75программы...Вообще говоря, С# не позволяет иметь в одной программе две функции с одинаковым!именами.
В конце концов, как тогда он сможет разобраться, какую из функций следует вызшвать? Но дело в том, что С# в имя функции во внутреннем представлении компилятора вклшчает не только имя функции, но и количество и типы ее аргументов. Поэтому С# в состояв!отличить функцию A v e r a g e A n d D i s p l a y ( s t r i n g , d o u b l e , s t r i n g , d o u b l e ) отфушции A v e r a g e A n d D i s p l a y ( d o u b l e , d o u b l e ) .
Если рассматривать эти функции с ихаигументами, становится очевидным, что они разные.Реализация аргументов по умолчаниюЗачастую оказывается желательно иметь две (или более) версии функции, имеюищследующие отличия.Одна из функций представляет собой более сложную версию, обеспечивающую большую гибкость, но требующую большого количества аргументов от вызывающей программы, причем некоторые из них для пользователя могут быть просто непонятны.Под пользователем функции зачастую подразумевается программист, прменяющий ее в своих программах, так что пользователь функции и полкватель готовой программы — это разные люди.
Еще один термин, примняемый для обозначения такого рода пользователя — клиент.Вторая версия функции гораздо проще для применения, она работаетже, как и первая, в которой часть аргументов принимает некоторые пдопределенные значения по умолчанию.Такое поведение легко реализуется с использованием перегрузки функций.Рассмотрим следующую пару функций D i s p l a y R o u n d e d D e c i m a l ( ) ://////154FunctionsWithDefaultArguments - две версии одной и тойфункции, причем одна из них п р е д с т а в л я е т версию второйиспользованием значений аргументов по умолчаниюжесЧасть III. Объектно-основанное программирован®usingSystem;namespaceF u n c t i o n s W i t h D e f a u l tA r g u m e n t s(publicclassProgram{publics t a t i cvoidMain(string[]args)// Вызов ф у н к ц и и - ч л е н а11C o n s o l e .
W r i t e L i n e ( " {0} ,DisplayRoundedDecimal(12.345678M,3));// Ожидаем п о д т в е р ж д е н и я п о л ь з о в а т е л яConsole.WriteLine("Нажмите <Enter> для " +"завершения программы...");Console.Read();}//DisplayRoundedDecimal//decimalвстрокус-преобразуетопределеннымзначениеколичествомтипазначащих// цифрpublics t a t i cstringDisplayRoundedDecimal(decimalintmValue,nNumberOfSignificantDigits){// Сначала округляем число до у к а з а н н о г о количества// значащих цифрdecimal mRoundedValue =decimal.Round(mValue,nNumberOfSignificantDigits);// и п р е о б р а з у е м е г о в с т р о к уstring s = Convert.ToString(mRoundedValue);returns,-}publics t a t i cstringDisplayRoundedDecimal(decimalmValue){// Вызываем D i s p l a y R o u n d e d D e c i m a l ( d e c i m a l ,int)с// у к а з а н и е м к о л и ч е с т в а значащих цифр по умолчаниюstring s = DisplayRoundedDecimal(mValue,2);returns;Функция D i s p l a y R o u n d e d D e c i m a l ( )п р е о б р а з у е т з н а ч е н и е т и п а d e c i m a l в значение типа s t r i n g с о п р е д е л е н н ы м к о л и ч е с т в о м з н а ч а щ и х ц и ф р п о с л е д е с я т и ч н о й точки.
Поскольку ч и с л а т и п а d e c i m a l ч а с т о п р и м е н я ю т с я в ф и н а н с о в ы х р а с ч е т а х , наиболее распространенными б у д у т в ы з о в ы э т о й ф у н к ц и и со в т о р ы м а р г у м е н т о м , р а в н ы м 2.В анализируемой п р о г р а м м е э т о п р е д у с м о т р е н о , и в ы з о в D i s p l a y R o u n d e d D e c i m a l ()с одним а р г у м е н т о м о к р у г л я е т з н а ч е н и е э т о г о а р г у м е н т а до д в у х ц и ф р п о с л е д е с я т и ч н о й'та 7.
Функции функций155точки, позволяя пользователю не беспокоиться о смысле и числовом значениивторойаргумента функции.Обратите внимание, что версия фунющи D i s p l a y R o u n d e d D e c i m a l ( d e c i m a lв действительности осуществляет вызов функции D i s p l a y R o u n d e d D e c i m a l( d e c i m a l , i n t ) .
Такая практика позволяет избежать ненужного дублировавкода. Обобщенная версия функции может использовать существенно большееколичество аргументов, которые ее разработчик может даже не включить док|кументацию.Аргументы по умолчанию не просто сберегают силы ленивого программнаПрограммирование — работа, требующая высочайшей степени концентрати излишние аргументы функции, для выяснения назначения и рекомендуемзначений которых необходимо обращаться к документации, затрудняют программирование, приводят к перерасходу времени и повышают вероятное!внесения ошибок в код. Автор функции хорошо понимает взаимосвязи меж!аргументами функции и способен обеспечить несколько корректных перегруженных версий функции, более дружественных к клиенту.Примечание для программистов на Visual Basic и C/C++: в С# единственный способреализации аргументов по умолчанию — это перегрузка функций.
С# не позволяет иметьнеобязательные аргументы.Передача в функцию типов-значенийБазовые типы переменных, такие как i n t , d o u b l e , d e c i m a l , известны как т и пзначения. Переменные таких типов могут быть переданы в функцию одним из двух способов. По умолчанию эти переменные передаются в функцию по значению (by valuеальтернативная форма — передача по ссылке.Программисты часто не совсем точны в употреблении терминов. Если речь идет типах-значениях, то когда программист говорит о "передаче переменной в функцию", этообычно означает "передача значения переменной в функцию".Передача по значениюВ отличие от ссылок на объекты, переменные с типами-значениями наподобие idили d o u b l e обычно передаются в функцию по значению, т.е.