Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Books / 3_C#_2005_для_чайников_(Дэвис-2008)

.pdf
Скачиваний:
86
Добавлен:
24.03.2015
Размер:
15.46 Mб
Скачать

Выполнение конструктора в отладчике

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

1. Соберите программу с помощью команды меню Build о Build Demonstrate-

DefaultConstructor.

2.Перед тем как приступить к выполнению программы в отладчике, устано­ вите точку останова на вызове Console.WriteLineО в конструкторе

MyOtherObject.

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

Puc. 11.1. Красная пиктограмма на серой полосе свидетельствует о на­ личии точки останова

3. Воспользуйтесь командой меню D e b u g ^ S t e p Into (или нажмите клавишу

<F11>).

Ваши меню, полосы инструментов и окна должны немного измениться, а откры­ вающая фигурная скобка функции M a i n () — оказаться выделенной желтым цве­ том фона.

4. Нажмите клавишу <F11> еще три раза и установите курсор мыши над пе­ ременной localObject (без щелчка).

Вы находитесь перед вызовом конструктора MyObject . Ваш экран должен вы­ глядеть примерно так, как на рис. 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.Еще раз нажмите клавишу <F11>.

Программа перейдет к точке останова в конструкторе M y O t h e r O b j e c t , как! казано на рис. 11.3. Как мы сюда попали? Последний вызов в Main () приводит к запуску конструктора MyObj e c t . Однако перед началом выполнения конструк тора С# инициализирует статический член класса MyObject, который являет объектом типа 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> вы остановитесь в начале конструктора MyObject . Обратите внимание, что вы еще раз попадете в конструктор O t h e r O b j e c t , но на этот раз, когда конструктор MyObjec t будет создавать статический член d y n a m i c O b j .

250

Часть

IV.

Объектно-ориентированное

программирова

Puc. 11.3. Перед вызовом конструктора MyObject управление передается конструктору MyOtherObj ect

Puc. 11.4. После выполнения конструктора MyOtherObject вы возвра­ щаетесь в точку его вызова

Глава 11. Классы

251

Непосредственная инициализация объекта - конструктор по умолчанию

Вы можете решить, что практически любой класс должен иметь конструктор! умолчанию некоторого вида, и в общем-то вы правы. Однако С# позволяет инициала ровать члены-данные непосредственно, с использованием инициализаторов.

Итак, класс 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

{

// Номера б а н к о в с к и х с ч е т о в н а ч и н а ю т с я с 1000 // н а з н а ч а ю т с я п о с л е д о в а т е л ь н о в в о з р а с т а ю щ е м s t a t i c i n t n N e x t A c c o u n t N u m b e r = 1 0 0 0 ;

// Для

к а ж д о г о с ч е т а п о д д е р ж и в а ю т с я е г о номер

i n t n A c c o u n t N u m b e r = + + n N e x t A c c o u n t N u m b e r ;

d o u b l e d B a l a n c e = 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 существует только как часть некоторого объекта. Таким образом, при сваивание не выполняется до тех пор, пока не будет создан объект BankAccount. Рас сматриваемое присваивание осуществляется всякий раз при создании объекта.

Заметим, что статический член-данные 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 c t o r перенесем вызов new 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 ( ) .

p u b l i c c l a s s MyObjec t

{

/ /

Этот

ч л е н

я в л я е т с я

с в о й с т в о м

к л а с с а

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

MyOtherObjectО;

p u b l i c

M y O b j e c t ( )

 

 

 

252

Часть

IV.

Объектно-ориентированное

программировав

Console . W r i t e L i n e ("Начало

к о н с т р у к т о р а

M y O b j e c t " ) ;

Console . WriteLine (" ( С т а т и ч е с к и е

члены "

+

" и н и ц и а л и з и р о в а н ы д о к о н с т р у к т о р а ) " ) ;

// Ранее з д е с ь с о з д а в а л с я

d y n a m i c O b j

 

Console . 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 ( )

 

Создание локального о б ъ е к т а MyObjec 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

 

Начало конструктора MyObjec t

 

(Статические члены и н и ц и а л и з и р о в а н ы до

к о н с т р у к т о р а )

Завершение к о н с т р у к т о р а MyObject

 

Н а ж м и т е < E n t e r > для з а в е р ш е н и я п р о г р а м м ы . . .

Полный текст данной программы можно найти на прилагаемом компактдиске в каталоге 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, "Функции функций").

Предположим, вы хотите обеспечить три способа создания объекта Bank - Account — с нулевым балансом, как и ранее, и два варианта с некоторыми начальными значениями.

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 s - б а н к о в с к и й с ч е т с разными вариантами конструкторов

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 s

Using System;

 

 

 

 

public class Program

 

 

 

 

{

 

 

 

 

public s t a t i c

v o i d

Main ( s t r i n g [ ]

a r g s )

{

 

 

 

 

// Создание

б а н к о в с к и х

с ч е т о в

с к о р р е к т н ы м и начальными

// значениями

 

 

 

BankAccount

b a l

= new

B a n k A c c o u n t ( ) ;

C o n s o l e . W r i t e L i n e ( b a l . G e t S t r i n g ( ) ) ;

Классы

253

B 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

(ba2 . 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 , 2 0 0 ) ;

C o n s o l e . W r i t e L i n e ( Ь а З . G e t S t r i n g ( ) ) ;

 

/ / Ожидаем

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

 

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

//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

{

//

Первый

номер с ч е т а

— 1 0 0 0 ;

номера с ч е т о в

 

/ / н а з н а ч а е т с я п о с л е д о в а т е л ь н о

 

 

 

 

s t a t i c i n t n N e x t A c c o u n t N u m b e r = 1 0 0 0 ;

 

 

//

Номер

с ч е т а и е г о

б а л а н с

 

 

 

 

 

i n t n A c c o u n t N u m b e r ;

 

 

 

 

 

 

d o u b l e d B a l a n c e ;

 

 

 

 

 

 

// Н е с к о л ь к о

к о н с т р у к т о р о в

- в

з а в и с и м о с т и

от

ваших

/ / п о т р е б н о с т е й

 

 

 

 

 

 

p u b l i c

B a n k A c c o u n t ( )

// А в т о м а т и ч е с к о г о к о н с т р у к т о р а нет

{

 

 

 

 

 

 

 

 

 

 

 

 

n A c c o u n t N u m b e r = + + n N e x t A c c o u n t N u m b e r ;

 

 

 

d B a l a n c e = 0 . 0 ;

 

 

 

 

 

 

}'

 

 

 

 

 

 

 

 

 

 

 

p u b l i c

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

 

 

{

 

 

 

 

 

 

 

 

 

 

 

 

/ /

П о в т о р е н и е ч а с т и

к о д а

и з к о н с т р у к т о р а

п о

умолчанию

 

n A c c o u n t N u m b e r = + + n N e x t A c c o u n t N u m b e r ;

 

 

 

//

Т е п е р ь —

к о д , специфичный

д ля

д а н н о г о

конструктора

 

//

Начинаем

с п е р е д а н н о г о

б а л а н с а

( е с л и

он

 

 

/ /

положительный)

 

 

 

 

 

 

 

if

( d l n i t i a l B a l a n c e < 0)

 

 

 

 

 

 

{

 

 

 

 

 

 

 

 

 

 

 

 

d l n i t i a l B a l a n c e = 0;

 

 

 

 

 

 

}

 

 

 

 

 

 

 

 

 

 

 

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

 

 

 

 

}

 

 

 

 

 

 

 

 

 

 

 

p u b l i c B a n k A c c o u n t ( i n t n l n i t i a l A c c o u n t N u m b e r ,

 

 

 

 

 

 

d o u b l e d l n i t i a l B a l a n c e )

 

 

{

 

 

 

 

 

 

 

 

 

 

 

 

/ /

Игнорируем о т р и ц а т е л ь н ы й

номер

с ч е т а

 

 

 

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.

Объектно-ориентированное программировал

n l n i t i a l A c c o u n t N u m b e r = + + n N e x t A c c o u n t N u m b e r ;

}

= n l n i t i a l A c c o u n t N u m b e r ;

nAccountNumber

// Начинаем с

п е р е д а н н о г о б а л а н с а ( е с л и он

//положительный)

if ( d l n i t i a l B a l a n c e < 0)

{

d l n i t i a l B a l a n c e = 0;

}

dBalance =

d l n i t i a l B a l a n c e ;

}

 

public s t r i n g

G e t S t r i n g ( )

{

r e t u r n S t r i n g . F o r m a t ( " # { 0 } = { l : N } " ,

n A c c o u n t N u m b e r , d B a l a n c e ) ;

Как только вы определили собственный конструктор — не имеет значения, ка­ кого именно типа, С# больше не создает конструктор по умолчанию для вашего класса. Поэтому нужно самим определить конструктор без параметров в этой демонстрационной программе.

В приведенной выше демонстрационной программе 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

Н а ж м и т е < E n t e r > дл я з а в е р ш е н и я п р о г р а м м ы . . .

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

Конструкторы различаются между собой по тем же правилам, что и перегруженные функции. Первый объект, конструируемый в функции Main ( ) , b a l , создается без аргументов, так что для него вызывается первый конструктор B a n k A c c o u n t ( ) , не получающий аргументов (он все еще именуется конструктором по умолчанию, хотя и не создается С# автоматически). Соответственно, этот счет получает номер по умолчанию и нулевой ба-

11. Классы

255

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

public c l a s s

B a n k A c c o u n t

(

 

 

 

/ / Первый

н о м е р

с ч е т а

— 1 0 0 0 ; н о м е р а с ч е т о в

/ / н а з н а ч а е т с я п о с л е д о в а т е л ь н о

s t a t i c i n t n N e x t A c c o u n t N u m b e r = 1 0 0 0 ;

/ / Номер

с ч е т а и

е г о

б а л а н с

i n t n A c c o u n t N u m b e r ;

 

double d B a l a n c e ;

 

 

/ / Р а з м е щ а е м в е с ь и н и ц и а л и з и р у ю щ и й к о д в о т д е л ь н о й / / ф у н к ц и и , в ы з ы в а е м о й и з к о н с т р у к т о р о в

p u b l i c B a n k A c c o u n t ( ) / / А в т о м а т и ч е с к о г о к о н с т р у к т о р а н е т

{

I n i t ( + + n N e x t A c c o u n t N u m b e r , 0 . 0 ) ;

p u b l i c B a n k A c c o u n t ( d o u b l e d l n i t i a l B a l a n c e )

{

I n i t ( + + n N e x t A c c o u n t N u m b e r , d l n i t i a l B a l a n c e ) ;

/ /

К о н с т р у к т о р с

н а и б о л ь ш и м к о л и ч е с т в о м а р г у м е н т о в

/ /

в ы п о л н я е т в с ю

р а б о т у

 

p u b l i c B a n k A c c o u n t ( i n t

n l n i t i a l A c c o u n t N u m b e r ,

 

 

d o u b l e

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

{

/ / Н а с а м о м д е л е т у т н а д о п р о в е р и т ь , ч т о б ы з н а ч е н и е / / n l n i t i a l A c c o u n t N u m b e r ( а ) н е с о в п а д а л о с у ж е

/ /

н а з н а ч е н н ы м и н о м е р а м и с ч е т о в и ( б ) б ы л о н е м е н ь ш е

//

1 0 0 0

 

 

I n i t ( n l n i t i a l A c c o u n t N u m b e r ,

d l n i t i a l B a l a n c e ) ;

p r i v a t e v o i d I n i t ( i n t

n l n i t i a l A c c o u n t N u m b e r ,

 

d o u b l e

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

{

n A c c o u n t N u m b e r = n l n i t i a l A c c o u n t N u m b e r ;

/ / И с п о л ь з у е м п е р е д а н н ы й б а л а н с ( е с л и о н п о л о ж и т е л е н )

i f ( d l n i t i a l B a l a n c e

< 0 )

{

 

d l n i t i a l B a l a n c e =

0 ;

}

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

}

p u b l i c s t r i n g G e t S t r i n g O

r e t u r n S t r i n g . F o r m a t ( " # { 0 } = { l : N } " ,

n A c c o u n t N u m b e r , d B a l a n c e ) ;

11. Классы

257

Здесь метод I n i t () выполняет всю работу, связанную с конструированием. Одни по ряду причин такой подход недостаточно " к о ш е р н ы й " — не в последнюю очередь! за того, что при этом вызывается метод объекта, который еще не полностью построй это очень опасная игра!

 

К счастью, такой подход не является необходимым . Один конструктор«

 

жет

обращаться к

другому с использованием ключевого слова t h i s а

 

д у ю щ и м

образом:

 

 

/ / B a n k A c c o u n t C o n t r u c t o r s A n d T h i s - б а н к о в с к и й с ч е т с

/ / н е с к о л ь к и м и к о н с т р у к т о р а м и

 

u s i n g S y s t e m ;

 

 

 

n a m e s p a c e B a n k A c c o u n t C o n t r u c t o r s A n d F u n c t i o n

{

 

 

 

 

 

u s i n g

S y s t e m ;

 

 

 

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 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 l = n e w B a n k A c c o u n t ( ) ; C o n s o l e . W r i t e L i n e ( b a l . G e t S t r i n g ( ) ) ;

B a n k A c c o u n t b a 2 = n e w 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 = n e w B a n k A c c o u n t ( 1 2 3 4 , 2 0 0 ) ;

C o n s o l e . W r i t e L i n e ( b a 3 . G e t S t r i n g ( ) ) ;

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

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

}

/ / 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

{

/ / П е р в ы й н о м е р с ч е т а — 1 0 0 0 ; н о м е р а с ч е т о в

/ /

н а з н а ч а е т с я п о с л е д о в а т е л ь н о

s t a t i c i n t n N e x t A c c o u n t N u m b e r = 1 0 0 0 ;

/ / Н о м е р с ч е т а и е г о б а л а н с

i n t

n A c c o u n t N u m b e r ;

d o u b l e d B a l a n c e ;

/ / В ы з ы в а е м к о н с т р у к т о р

с н а и б о л ь ш и м к о л и ч е с т в о м

/ / а р г у м е н т о в , п е р е д а в а я з н а ч е н и я п о у м о л ч а н и ю д л я

/ /

о т с у т с т в у ю щ и х п а р а м е т р о в

258

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

p u b l i c

B a n k A c c o u n t ( )

: t h i s ( 0 ,

0 )

{ }

p u b l i c

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

: t h i s ( 0 , d l n i t i a l B a l a n c e )

{ }

 

/ /

К о н с т р у к т о р с н а и б о л ь ш и м к о л и ч е с т в о м а р г у м е н т о в

/ /

в ы п о л н я е т в с ю р а б о т у

p u b l i c B a n k A c c o u n t ( i n t n l n i t i a l A c c o u n t N u m b e r , d o u b l e d l n i t i a l B a l a n c e )

{

/ / И г н о р и р у е м о т р и ц а т е л ь н ы е н о м е р а с ч е т о в ; н у л е в о е / / з н а ч е н и е о з н а ч а е т , ч т о м ы х о т и м и с п о л ь з о в а т ь / / о ч е р е д н о е с в о б о д н о е з н а ч е н и е н о м е р а с ч е т а

i f ( n l n i t i a l A c c o u n t N u m b e r < = 0 )

{

n l n i t i a l A c c o u n t N u m b e r = + + n N e x t A c c o u n t N u m b e r ;

}

n A c c o u n t N u m b e r = n l n i t i a l A c c o u n t N u m b e r ;

/ / И с п о л ь з у е м п е р е д а н н ы й б а л а н с ( е с л и о н п о л о ж и т е л е н ) if ( d l n i t i a l B a l a n c e < 0)

{

d l n i t i a l B a l a n c e = 0 ;

}

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

p u b l i c s t r i n g G e t S t r i n g ( )

{

r e t u r n S t r i n g . F o r m a t ( " # { 0 } = { l : N } " ,

n A c c o u n t N u m b e r , d B a l a n c e ) ;

В этой версии класса 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

( ) :

 

 

 

 

BankAccount b a l =

n e w

B a n k A c c o u n t ( )

;

/ / П а р а м е т р о в н е т

Конструктор B a n k A c c o u n t

()

тут же

передает

управление конструктору B a n k A c ­

count ( i n t , d o u b l e ) , передавая ему значения по умолчанию 0 и 0.0:

public B a n k A c c o u n t

()

:

t h i s ( 0 ,

0)

{}

 

Поскольку тело конструктора пустое, весь конструктор можно смело записы­ вать в одну строку.

Глава 11. Классы

259