1629295403-b876e2087bddebea4bc9666fb2377a02 (846199), страница 46
Текст из файла (страница 46)
Рождение объекта — одиниз самых важных этапов в его жизни. Класс, конечно, может предоставить метод доинициализации вновь созданного объекта, но беда в том, что приложение может попросту забыть его вызвать. В таком случае члены-данные класса окажутся заполнен]"мусором", и корректной работы от такого объекта ждать не придется.С# решает эту проблему путем вызова инициализирующей функции автоматиченНапример, в строке•MyObjectmo=new M y O b j e c t O ;не только выделяется память для объекта, но и выполняется его инициализация посредством вызова специальной инициализирующей функции.Не путайте термины класс и объект. D o g — это класс, но собака Scooter-Iэто объект класса Dog.С# хорошо умеет отслеживать инициализацию переменных и не позволяет исполинвать неинициализированные переменные. Например, представленный далее код приведяк генерации ошибки компиляции:publicstatic void Main(string[]args){int n ;d o u b l e d;double dCalculatedValue= n+d;}244ЧастьIV.Объектно-ориентированноепрограммированыС# отслеживает тот факт, что ни n, ни d не и м е ю т присвоенного значения и не могутиспользоваться в выражении.
Компиляция этой микропрограммы приводит к генерацииследующих ошибок:Use of u n a s s i g n e d l o c a l v a r i a b l e 'n'Use of u n a s s i g n e d l o c a l v a r i a b l e 'd'Однако C# предоставляет конструктор по умолчанию для объектов классов, которыйинициализирует члены-данные значением 0 для встроенных переменных, f a l s e — длялогических и n u l l — для ссылок. Рассмотрим с л е д у ю щ у ю простую демонстрационнуюпрограмму:using System;namespace T e s t(public c l a s s P r o g r a m{public s t a t i c v o i d M a i n ( s t r i n g []args){// С н а ч а л а с о з д а е м о б ъ е к тMyObject l o c a l O b j e c t = n e w M y O b j e c t O ;Console.WriteLine("localObject.n = { o } " , localObject.n);if ( l o c a l O b j e c t .
n e x t O b j e c t == n u l l ){Console.WriteLine("localObject.nextObject=null");}// О ж и д а е м п о д т в е р ж д е н и я п о л ь з о в а т е л яConsole.WriteLine("Нажмите <Enter> для " +"завершения программы.. . " ) ;Console.Read();public class M y O b j e c t{internal int n;internal M y O b j e c t n e x t O b j e c t ;Эта программа определяет класс M y O b j e c t , который содержит переменную п типаint и ссылку на объект n e x t O b j e c t , позволяющую создавать связанные списки объектов.
Функция M a i n () создает объект класса M y O b j e c t и выводит начальное содержимое его членов. Вывод этой программы имеет видlocalObject .п = ОlocalObject . n e x t O b j e c t = n u l lНажмите <Enter> д л я з а в е р ш е н и я п р о г р а м м ы . . .С# при создании объекта выполняет небольшой код по ишшиализации объекта и его членов. Если бы не этот код, члены-данные l o c a l O b j e c t . п и l o c a l O b j e c t . n e x t O b j ectсодержали бы какие-то случайные значения, попросту говоря — "мусор".[Сод, инициализирующий значения при создании, называется конструктором.Эн "конструирует" класс в смысле инициализации его членов.Глава 11. Классы245С# гарантирует, что объект начинает существование в определенном состоянии:полненным нулями.
Однако для многих классов (пожалуй, для подавляющего большенства) такое нулевое состояние не является корректным. Рассмотрим класс BankАc o u n t , о котором уже шла речь ранее в этой главе,publicclassBankAccount{int n A c c o u n t N u m b e r ;double dBalance;I I . . . д р у г и ечлены}Хотя нулевое начальное значение баланса вполне корректно, нулевое значение номра счета определенно корректным не является.Поэтому класс B a n k A c c o u n t включает метод I n i t B a n k A c c o u n t ( ) , инициализирующий объект. Однако такой подход перекладывает слишком большую ответственость на прикладную программу, использующую данный класс.
Если вдруг приложензабудет вызвать метод I n i t B a n k A c c o u n t ( ) , то прочие методы банковского счетагут оказаться неработоспособны, хотя при этом и не будут содержать никаких ошибокКласс не должен полагаться на внешние функциинаподобие методаInitBankAc o u n t ( ) , которые должны обеспечивать корректное состояние его объектов.Для решения данной проблемы класс предоставляет специальную функцию, автоматически вызываемую С# при создании объекта — конструктор класса.
С# требует, чтобы конструктор носил то же имя, что и имя самого класса, так что конструктор классаB a n k A c c o u n t имеет следующий вид:public void Main(string[]args){BankAccount ba = new B a n k A c c o u n t ( ) ;}publicclassBankAccount{// Н о м е р а б а н к о в с к и х с ч е т о в н а ч и н а ю т с я с 1000 и// назначаются последовательно в возрастающем порядкеstatic int n N e x t A c c o u n t N u m b e r = 1 0 0 0 ;// Для каждого счета поддерживаются его номер и балансint n A c c o u n t N u m b e r ;double dBalance;/ / К о н с т р у к т о р B a n k A c c o u n t - о б р а т и т е в н и м а н и е н а е г о имяpublic BankAccount() // Требуются круглые скобки, могут// иметься аргументы, возвращаемый// тип о т с у т с т в у е т{nAccountNumber =d B a l a n c e = 0.0;++nNextAccountNumber;}I I .
. .прочиечлены...}246ЧастьIV.Объектно-ориентированноепрограммированаСодержимое конструктора B a n k A c c o u n t то же, что и у первоначального методаInitBankAccount (). Однако конструктор имеет некоторые особенности:он всегда имеет то же имя, что и сам класс;он не имеет возвращаемого типа, даже типа v o i d ;функция M a i n ()не должна вызывать никаких дополнительных функций дляинициализации объекта при его создании.Создание объектовТеперь посмотрим на конструкторы в деле.
Д л я этого рассмотрим программу 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 e t o r .// DemonstrateDef a u l t C o n s t r u c t o r - д е м о н с т р а ц и я р а б о т ы// конструкторов по у м о л ч а н и ю ; с о з д а е т к л а с с с к о н с т р у к т о р о м// и рассматриваем н е с к о л ь к о с ц е н а р и е вusing System;namespaceIDemonstrateDef aultConstructor// MyObject - с о з д а н и е к л а с с а с " м н о г о с л о в н ы м "// конструктором и в н у т р е н н и м о б ъ е к т о мpublic class M y O b j e c tI// Этот ч л е н - д а н н ы е я в л я е т с я с в о й с т в о м к л а с с аstatic M y O t h e r O b j e c t s t a t i c O b j = n e w M y O t h e r O b j e c t ( ) ;// Этот ч л е н - д а н н ы е я в л я е т с я с в о й с т в о м о б ъ е к т аMyOtherObject d y n a m i c O b j ;// К о н с т р у к т о р (с о б и л ь н ы м в ы в о д о м на э к р а н )public M y O b j e c t O{Console.WriteLine("Начало конструктора M y O b j e c t " ) ;Console.WriteLine("(Статические члены-данные " +" к о н с т р у и р у ю т с я до в ы з о в а э т о г о " +" к о н с т р у к т о р а )11) ;Console.WriteLine("Теперь динамически создаем " +" н е с т а т и ч е с к и й ч л е н - д а н н ы е : ") ;dynamicObj = n e w M y O t h e r O b j e c t О ;Console.WriteLine("Завершение конструктора M y O b j e c t " ) ;// MyOtherObject - у э т о г о к л а с с а т о ж е м н о г о с л о в н ы й// конструктор, но в н у т р е н н и е ч л е н ы - д а н н ы е о т с у т с т в у ю тpublic class M y O t h e r O b j e c tpublic M y O t h e r O b j e c t (){.Console.WriteLine("КонструированиеГлава 11, КлассыMyOtherObject");247publicclassProgram{publicstatic void Main(string[]args){Console.WriteLine("Начало функции M a i n ( ) " ) ;Console.WriteLine("Создание локального объекта"MyObject в M a i n ( ) : " ) ;MyObject localObject = new M y O b j e c t O ;"+// Ожидаем подтверждения пользователяConsole.WriteLine("Нажмите <Enter> для " +"завершения п р о г р а м м ы .
. . " ) ;Console.Read();}1}}Выполнение данной программы приводит к следующему выводу на экран:Начало функции Main()Создание локального объекта MyObject в M a i n O :Конструирование MyOtherObjectНачало конструктора MyObject(Статические члены-данные конструируются до вызоваэтого конструктора)Теперь динамически создаем нестатический член-данные:Конструирование MyOtherObjectЗавершение конструктора MyObjectНажмите <Enter> для завершения программы...Вот реконструкция происходящего при запуске программы.1. Программа начинает работу, и функция M a i n () выводит начальное сообщениесообщение о предстоящем создании локального объекта M y O b j e c t .2.
Функция M a i n () создает объект l o c a l O b j e c t типа M y O b j e c t .3. M y O b j e c t содержит статический член s t a t i c O b j класса MyOtherObject. Встатические члены-данные создаются до первого запуска конструктора MyObjectВ этом случае С# присваивает переменной s t a t i c O b j ссылку на вновь создан»объект перед тем, как передать управление конструктору M y O b j e c t .4. Конструктор M y O b j e c t получает управление. Он выводит начальное сообщаи напоминает, что статический член уже сконструирован до того, как начал palту конструктор M y O b j e c t О .5. После объявления о своих намерениях по динамическому созданию нестатнского члена конструктор M y O b j e c tсоздает объект класса MyOtherObjectиспользованием оператора n e w , что сопровождается выводом второго сообщао создании M y O t h e r O b j e c t на экран.6.
Управление возвращается конструктору M y O b j e c t , который, в свою очередьвозвращает управление функции M a i n ().7. Программа выполнена.248ЧастьIV.Объектно-ориентированноепрограммировавВыполнение конструктора в отладчикеДля того чтобы выполнить рассматриваемую программу в отладчике, произведитеследующие действия.1. Соберите программу с помощью команды менюDefaultConstructor.Build о Build Demonstrate-2. Перед тем как приступить к выполнению программы в отладчике, установите точку останова на вызове Console.WriteLineОв конструктореMyOtherObject.Для установки точки останова щелкните на сером поле с левой стороны окнанапротив строки, в которой хотите разместить точку останова.
На рис. 11.1 показано окно отладки с точкой останова, о чем свидетельствует красная пиктограмма на серой полосе.Puc. 11.1. Красная пиктограмма на серой полосе свидетельствует о наличии точки останова3. Воспользуйтесь<F11>).командой менюD e b u g ^ S t e p Into(или нажмите клавишуВаши меню, полосы инструментов и окна должны немного измениться, а открывающая фигурная скобка функции M a i n () — оказаться выделенной желтым цветом фона.4.
Нажмите клавишу <F11> еще три раза и установите курсор мыши над переменной localObject (без щелчка).Вы находитесь перед вызовом конструктора M y O b j e c t . Ваш экран должен выглядеть примерно так, как на рис. 11.2. На рисунке видно, что в настоящий мо-toa 77. Классы249мент объект l o c a l O b j e c t под курсором имеет значение n u l l . То же показывает и окно Locals.Рис. 11.2. Окно отладчика Visual Studio перед выполнением конструктора5.