1629295403-b876e2087bddebea4bc9666fb2377a02 (846199), страница 47
Текст из файла (страница 47)
Еще раз нажмите клавишу <F11>.Программа перейдет к точке останова в конструкторе M y O t h e r O b j e c t , как!казано на рис. 11.3. Как мы сюда попали? Последний вызов в M a i n () приводитк запуску конструктора MyObj e c t . Однако перед началом выполнения конструктора С# инициализирует статический член класса M y O b j e c t , который являетобъектом типа M y O t h e r O b j e c t , так что инициализация подразумевает вызовего к о н с т р у к т о р а — где и находится точка останова (без нее нельзя было бы остановить здесь отладчик, хотя сам конструктор был бы выполнен — вы бы моглисудить об этом по сообщению в окне консоли).6.
Дважды нажмите клавишу <F11>, после чего вы остановитесь на строке!статическим членом s t a t i c O b j , как показано на рис. 11.4.Это означает, что конструктор этого объекта завершил свою работу.7. Продолжайте нажимать клавишу <F11> для пошагового выполнения прграммы.При первом нажатии клавиши <F11> вы остановитесь в начале конструктораM y O b j e c t .
Обратите внимание, что вы еще раз попадете в конструкторO t h e r O b j e c t , но на этот раз, когда конструктор M y O b j e c t будет создаватьстатический член d y n a m i c O b j .250ЧастьIV.Объектно-ориентированноепрограммироваPuc. 11.3. Перед вызовом конструктора MyObject управление передаетсяконструктору MyOtherObj ectPuc.
11.4. После выполнения конструктора MyOtherObject вы возвращаетесь в точку его вызоваГлава 11. Классы251Непосредственная инициализация объекта конструктор по умолчаниюВы можете решить, что практически любой класс должен иметь конструктор!умолчанию некоторого вида, и в общем-то вы правы. Однако С# позволяет инициаларовать члены-данные непосредственно, с использованием инициализаторов.Итак, класс B a n k A c c o u n t можно записать следующим образом:publicclassBankAccount{// Номера б а н к о в с к и х с ч е т о в н а ч и н а ю т с я с 1000 и// назначаются п о с л е д о в а т е л ь н о в возрастающем порядкеs t a t i c i n t nNextAccountNumber = 1000;/ / Для к а ж д о г о с ч е т а п о д д е р ж и в а ю т с я е г о н о м е р и б а л а н сi n t nAccountNumber = ++nNextAccountNumber;double dBalance = 0.0;I I .
. . прочие члены ...}Вот в чем состоит работа инициализаторов. Как n A c c o u n t N u m b e r , так и dBalanceполучают значения как часть объявления, эффект которого аналогичен использованномууказанного кода в конструкторе.Надо очень четко представлять себе картину происходящего. Вы можете решить, чтоэто выражение присваивает значение 0 . 0 переменной d B a l a n c e непосредственно. Оведь d B a l a n c e существует только как часть некоторого объекта. Таким образом, присваивание не выполняется до тех пор, пока не будет создан объект B a n k A c c o u n t .
Рассматриваемое присваивание осуществляется всякий раз при создании объекта.Заметим, что статический член-данные n N e x t A c c o u n t N u m b e r инициализируетсяпри самом первом обращении к классу B a n k A c c o u n t (как вы убедились при выполненнии демонстрационной программы в отладчике), т.е. обращении к любому свойству илиметоду объекта, владеющему статическим членом, в том числе и конструктору. Буду чиинициализирован, статический член повторно не инициализируется, сколько бы обитов вы не создавали. Этим он отличается от нестатических членов.Инициализаторы выполняются в порядке их появления в объявлении класса.
Если ()встречает и инициализаторы, и конструктор, то инициализаторы выполняются до выведенения тела конструктора.Конструирование с инициализаторамиДавайте в рассматривавшейся ранее программе D e m o n s t r a t e D e f a u l t C o n s t r u ct o r перенесем вызов n e w M y O t h e r O b j e c t () из конструктора M y O b j e c t в объявление так, как показано в приведенном далее фрагменте исходного текста полужирнымшрифтом, и изменим второй вызов W r i t e L i n e ( ) .public{classMyObject/ / Этот член я в л я е т с я с в о й с т в о м к л а с с аs t a t i c M y O t h e r O b j e c t s t a t i c O b j = new M y O t h e r O b j e c t ( ) ;/ / Этот ч л е н я в л я е т с я с в о й с т в о м о б ъ е к т аM y O t h e r O b j e c t d y n a m i c O b j = new M y O t h e r O b j e c t О ;publicMyObject()252ЧастьIV.Объектно-ориентированноепрограммировавConsole .
W r i t e L i n e ( " Н а ч а л о к о н с т р у к т о р а M y O b j e c t " ) ;C o n s o l e . W r i t e L i n e (" ( С т а т и ч е с к и е ч л е н ы " +"инициализированы до к о н с т р у к т о р а ) " ) ;/ / Ранее з д е с ь с о з д а в а л с я d y n a m i c O b jConsole . W r i t e L i n e ( " З а в е р ш е н и е к о н с т р у к т о р а M y O b j e c t " ) ;Сравните вывод на экран такой модифицированной программы с выводом на экран•сходной программы D e m o n s t r a t e D e f a u l t C o n s t r u c t o r .Начало функции M a i n ( )Создание л о к а л ь н о г о о б ъ е к т а M y O b j e c t в M a i n ( ) :Конструирование M y O t h e r O b j e c tКонструирование M y O t h e r O b j e c tНачало конструктора MyObject(Статические ч л е н ы и н и ц и а л и з и р о в а н ы д о к о н с т р у к т о р а )Завершение к о н с т р у к т о р а M y O b j e c tНажмите<Enter> длязавершенияп р о г р а м м ы .
. .Полный текст данной программы можно найти на прилагаемом компактдиске в каталоге D e m o n s t r a t e C o n s t r u c t o r W i t h l n i t i a l i z e r .Конструкторы можно перегружать так же, как и прочие методы.Перегрузка функции обозначает определение двух функций с одним и тем жеименем, но с разными типами аргументов (подробно этот вопрос рассматривается в главе 7, "Функции функций").Предположим, вы хотите обеспечить три способа создания объекта B a n k A c c o u n t — с нулевым балансом, как и ранее, и два варианта с некоторыминачальными значениями.BankAccountWithMultipleConstructorsразными вариантами конструкторовUsing System;-банковскийсчетсH o m e s p а с еB a n k A c c o u n t W i t h M u l t i p l e C o n s t r u c t o r sUsing S y s t e m ;public class Program{publicstaticvoidMain ( s t r i n g []args){// Создание б а н к о в с к и х с ч е т о в с к о р р е к т н ы м и// з н а ч е н и я м иBankAccount b a l = n e w B a n k A c c o u n t ( ) ;Console.WriteLine(bal.GetString());Классыначальными253B a n k A c c o u n t Ьа2 = new B a n k A c c o u n t ( 1 0 0 ) ;C o n s o l e .
W r i t e L i n e ( b a 2 . G e t S t r i n g (.)).;B a n k A c c o u n t b a 3 = new B a n k A c c o u n t ( 1 2 3 4 ,Console.WriteLine(ЬаЗ.GetString());200);/ / Ожидаем п о д т в е р ж д е н и я п о л ь з о в а т е л яConsole.WriteLine("Нажмите <Enter> для " +"завершения п р о г р а м м ы . . . " ) ;Console.Read();// BankAccount - простейшийp u b l i c c l a s s BankAccount{банковский//Первый номерсчета — 1000;//назначаетсяпоследовательноstaticint////=счетов1000;балансНесколько конструкторовпотребностейpublicномераnNextAccountNumber/ / Номер с ч е т а и е г оi n t nAccountNumber;double dBalance;счетBankAccount()//-взависимостиАвтоматическогоотвашихк о н с т р у к т о р а нет{nAccountNumber = ++nNextAccountNumber;dBalance = 0.0;}'publicBankAccount(doubledlnitialBalance){// Повторение части кода из конструктораnAccountNumber = ++nNextAccountNumber;//////ifпоумолчаниюТеперь — к о д , специфичный для д а н н о г о конструктораНачинаем с п е р е д а н н о г о б а л а н с а (если онположительный)( d l n i t i a l B a l a n c e < 0){dlnitialBalance=0;}dBalance=dlnitialBalance;}publicBankAccount(int nlnitialAccountNumber,doubledlnitialBalance){//ifИгнорируем отрицательный номер( n l n i t i a l A c c o u n t N u m b e r <= 0)счета{254НастьIV.Объектно-ориентированноепрограммировалnlnitialAccountNumber =}nAccountNumber=++nNextAccountNumber;nlnitialAccountNumber;// Начинаем с п е р е д а н н о г о// п о л о ж и т е л ь н ы й )if ( d l n i t i a l B a l a n c e < 0)баланса(еслион{dlnitialBalance=0;}dBalance=dlnitialBalance;}publicstringG e t S t r i n g (){returnString.Format("#{0} = {l:N}",nAccountNumber,dBalance);Как только вы определили собственный конструктор — не имеет значения, какого именно типа, С# больше не создает конструктор по умолчанию для вашегокласса.
Поэтому нужно самим определить конструктор без параметров в этойдемонстрационной программе.В приведенной выше демонстрационной программе B a n k A c c o u n t W i t ^ h M u l t i pleConstructors имеются три конструктора:первый назначает номер счета и нулевой баланс;второй назначает номер счета и инициализирует баланс переданным положительным значением (отрицательные значения игнорируются);третий позволяет пользователю самостоятельно определить номер счета и положительный начальный баланс.Функция Main () создает различные банковские счета с использованием каждого изipex конструкторов и выводит информацию о созданных объектах. Вывод этой прочимы на экран имеет следующий вид:#1001 = 0 .
0 0#1002 = 1 0 0 . 00# 1 2 3 4= 2 0 0 0 0Нажмите <Enter> для завершения п р о г р а м м ы . . .В реальных классах требуется выполнять более строгую проверку входных параметров конструктора, чтобы гарантировать их корректность.Конструкторы различаются между собой по тем же правилам, что и перегруженныефункции. Первый объект, конструируемый в функции M a i n ( ) , b a l , создается без аргументов, так что для него вызывается первый конструктор B a n k A c c o u n t ( ) , не получающий аргументов (он все еще именуется конструктором по умолчанию, хотя и не создаетсяС# автоматически). Соответственно, этот счет получает номер по умолчанию и нулевой ба-11. Классы255// BankAccount - б а н к о в с к и йpublic c l a s sBankAccountсчет(/ / Первый н о м е р с ч е т а — 1 0 0 0 ; н о м е р а с ч е т о в// н а з н а ч а е т с я п о с л е д о в а т е л ь н оstatic i n t nNextAccountNumber = 1000;/ / Номер с ч е т а и е г оint n A c c o u n t N u m b e r ;double d B a l a n c e ;баланс// Размещаем в е с ь инициализирующий к о д в// функции,вызываемой из к о н с т р у к т о р о вpublicBankAccount()//Автоматическогоотдельнойконструкторанет{Init(++nNextAccountNumber,publicBankAccount(double0.0);dlnitialBalance){Init(++nNextAccountNumber,dlnitialBalance);// К о н с т р у к т о р с наибольшим к о л и ч е с т в о м а р г у м е н т о в// выполняет всю р а б о т уpublic B a n k A c c o u n t ( i n tnlnitialAccountNumber,doubledlnitialBalance){////////InНа самом деле тут надо п р о в е р и т ь ,чтобы значениеnlnitialAccountNumber(а)не с о в п а д а л о с уженазначенными номерами счетов и(б)было не меньше1000it(nlnitialAccountNumber,dlnitialBalance);privatevoidI n i t ( i n tdoublenlnitialAccountNumber,dlnitialBalance){nAccountNumber//if=nlnitialAccountNumber;Используем переданный(dlnitialBalance <0)баланс(еслионположителен){dlnitialBalance=0;}dBalance=dlnitialBalance;}publicstringreturnGetStringOString.Format("#{0}={l:N}",nAccountNumber,11.