Documente Academic
Documente Profesional
Documente Cultură
Step by Step
Julian Templeman
Contents at a Glance
Introduction xxi
Part I
Chapter 1
Hello C++!
Chapter 2
13
Chapter 3
23
Chapter 4
Using functions
37
Chapter 5
57
Chapter 6
77
Chapter 7
Chapter 8
Inheritance 121
Part II
Chapter 9
Value types
143
Chapter 10
Operator overloading
159
Chapter 11
Exception handling
175
Chapter 12
197
Chapter 13
Properties 229
Chapter 14
245
Chapter 15
263
Part III
Chapter 16
281
Chapter 17
305
Chapter 18
Using ADO.NET
333
Chapter 19
351
Chapter 20
369
Chapter 21
397
103
Part IV
ADVANCED TOPICS
Chapter 22
437
Chapter 23
453
Chapter 24
475
Index 487
vi
Contents at a Glance
Contents
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxi
Part I
What s C++/CLI?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Creat ng a project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Bu d ng the executab e . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11
Conc us on. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11
Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11
13
13
14
Encapsu at on. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14
Inher tance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
Po ymorph sm. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
15
16
vii
16
A s mp e examp e. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
17
Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
22
23
What s a var ab e? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
23
23
Dec ar ng a var ab e. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
25
25
26
26
27
Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
28
Constants. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
28
Typedefs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
29
29
30
30
Ar thmet c operators. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
30
31
B tw se operators. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
32
33
Type cast ng . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
33
34
Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
viii Contents
35
37
38
38
39
39
40
41
Ca ng funct ons. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
45
47
51
Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
55
57
57
57
61
62
64
65
65
67
Perform ng oops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
68
Us ng while oops. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
68
Us ng for oops. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
70
Us ng do-while oops. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
71
73
Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
75
77
78
79
81
Creat ng objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
83
In t a z ng objects by us ng constructors. . . . . . . . . . . . . . . . . . . . . . . . . . . .
84
Defin ng constructors. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
84
86
87
88
90
C ass constructors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
92
Contents
ix
Us ng constants n c asses. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
93
Us ng c ass-w de constants. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
93
Us ng nstance constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
94
95
95
96
97
100
101
103
103
105
Destructors. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
105
F na zers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
106
107
110
Copy constructors. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
113
116
Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
119
122
122
x Contents
121
123
123
124
126
129
130
131
Protected access. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
136
137
Part II
137
138
Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
139
143
143
144
Propert es of va ue types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
145
Structures. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Creat ng and us ng a s mp e struct. . . . . . . . . . . . . . . . . . . . . . . . . . .
146
146
147
149
149
150
Copy ng structures. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
152
Enumerat ons. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Creat ng and us ng an enumerat on. . . . . . . . . . . . . . . . . . . . . . . . . .
153
153
155
156
Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
156
159
159
160
160
161
161
161
163
Contents
xi
166
167
171
172
173
Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
175
175
177
Except on types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
178
178
180
180
182
183
184
185
188
189
189
191
192
Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
195
xii Contents
174
197
197
200
In t a z ng arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
202
202
203
Gener c types. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
205
Managed arrays. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
207
212
213
215
Us ng enumerators. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
218
219
219
222
224
224
227
229
230
231
Errors n propert es . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
232
233
233
235
236
236
239
240
240
241
Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
244
245
245
246
Defin ng de egates. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
247
247
Contents
xiii
254
256
Hook ng t a together. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
258
Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
262
263
263
264
264
264
265
265
Assemb es. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
266
Metadata. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
266
268
270
270
272
273
274
The IO namespace. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
274
275
275
275
276
276
277
Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
xiv Contents
253
278
Part III
281
282
283
Us ng TextWriter. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
283
286
Us ng TextReader. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
287
290
290
298
298
299
Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
303
305
305
306
306
307
315
Wr t ng XML by us ng XmlTextWriter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
318
Us ng XmlDocument. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
322
323
323
325
Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
332
333
334
334
335
336
Contents
xv
336
Connect ng to a database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
337
340
341
342
344
345
Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
350
352
Serv ces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
352
Connect v ty. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
353
353
Endpo nts. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
353
Address . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
354
B nd ng. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
355
Contract. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
356
357
Behav ors. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
358
359
Wr t ng a serv ce c ent. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
361
363
365
Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
xvi Contents
351
368
369
369
369
370
W ndows Forms. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
370
371
371
Wh ch UI brary to choose?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
372
372
373
374
375
379
Introduc ng XAML. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
380
What s XAML?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
380
XAML syntax. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
381
XAML contro s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
382
Layout contro s. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
384
389
389
W ndows RT
390
Metadata. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
390
C++/CX syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
391
Common namespaces. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
393
Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
395
397
397
398
401
403
Perform ng ca cu at ons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
407
410
412
416
Us ng app bars. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
425
428
Where next?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
433
Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
433
Contents
xvii
Part IV
ADVANCED TOPICS
437
M xed c asses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
437
438
P nn ng and box ng
Inter or po nters. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
440
441
P nn ng po nters. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
441
442
Box ng . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
443
Unbox ng. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
443
444
447
Pass ng structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
449
Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
452
453
453
454
457
457
458
461
463
463
463
467
467
469
470
Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
xviii Contents
437
472
475
476
476
476
477
480
481
483
485
Index 487
Contents
xix
Introduction
++ s a powerfu , ndustr a -strength programm ng anguage used n tens of thousands of app cat ons around the wor d, and th s book w show you how to get
started us ng C++ on W ndows
Of a the anguages supported by M crosoft, C++ g ves you access to the w dest
range of techno og es on the W ndows p atform, from wr t ng games, through ow- eve
system software, to ne-of-bus ness app cat ons Th s book s go ng to ntroduce you to
severa of the areas n wh ch C++ s used n W ndows deve opment
For over a decade NET has become estab shed as the way to wr te desktop app cat ons for W ndows, and t prov des a wea th of techno og es to support deve opers
C++/CLI s the var ant of C++ that runs n the NET env ronment, and you can use t,
a ong w th other anguages such as C#, to create r ch desktop app cat ons
More recent y, W ndows 8 has ntroduced many new features to the W ndows operat ng system, but perhaps the most exc t ng s the debut of W ndows Store app cat ons
These graph ca app cat ons are des gned to run on touch screen and mob e dev ces,
and prov de a comp ete y new way to construct user nterfaces on W ndows C++ s one
of the ma n anguages supported for W ndows Store deve opment, and th s book w
g ve you an ntroduct on to these app cat ons and how to deve op them n C++/CX,
another var ant of C++ ntroduced spec fica y for th s purpose
xxi
Assumptions
Th s book expects that you have some exper ence of programm ng n a h gh- eve
anguage, so that you are fam ar w th concepts such as funct ons and arrays It s qu te
suffic ent to have exper ence n a procedura anguage such as V sua Bas c, and I do not
assume that you have any exper ence of object-or ented programm ng n genera , or of
C++ n part cu ar (a though any know edge of a cur y bracket anguage w be usefu )
xxiiIntroduction
Part I, Gett ng Started, ntroduces the ma n parts of the C++ anguage, gett ng
you used to cod ng n C++ and bu d ng app cat ons n V sua Stud o 2012
Part II, M crosoft NET Programm ng Bas cs, cont nues by ntroduc ng those
parts of C++ that are spec fic to M crosofts C++/CLI anguage
Part III, Us ng the NET Framework, covers the ma n features n the NET
Framework brar es used for wr t ng NET app cat ons Th s part nc udes
d scuss on of work ng w th fi es, XML and databases, and creat ng graph ca
app cat ons
Part IV, Advanced Top cs, covers some more advanced mater a , nc ud ng
deta s for work ng w th egacy code
New to C++
Fam ar w th C++
Most of the books chapters nc ude exerc ses that et you try out the concepts you
have just earned So ut ons to these exerc ses can be down oaded us ng the compan on
code nk from th s books web page on ore y com See the Code samp es sect on for
deta s on how to down oad the compan on code
Each exerc se cons sts of a ser es of tasks, presented as numbered steps (1, 2,
and so on) st ng each act on you must take to comp ete the exerc se
Boxed e ements w th abe s such as Note prov de add t ona nformat on or
a ternat ve methods for comp et ng a step successfu y
Text that you type (apart from code b ocks) appears n bo d
A p us s gn (+) between two key names means that you must press those keys at
the same t me For examp e, Press A t+Tab means that you ho d down the A t
key wh e you press the Tab key
A vert ca bar between two or more menu tems (e g , F e C ose) means that
you shou d se ect the first menu or menu tem, then the next, and so on
Introductionxxiii
System requirements
You w need the fo ow ng hardware and software to comp ete the pract ce exerc ses n
th s book
Depend ng on your W ndows configurat on, you m ght requ re Loca Adm n strator
r ghts to nsta or configure V sua Stud o 2012
Code samples
Most of the chapters n th s book nc ude exerc ses that et you nteract ve y try out new
mater a earned n the ma n text A samp e projects, n both the r pre-exerc se and
post-exerc se formats, can be down oaded from the fo ow ng page
http://aka.ms/VCCLISbS/files
xxivIntroduction
Acknowledgments
Produc ng a book nvo ves a number of peop e, and Id ke to thank the fo ow ng n
part cu ar
Id ke to thank a at M crosoft Press and ORe y for the r he p and support, espec a y Devon Musgrave at M crosoft for nv t ng me to start th s project, and Russe
Jones at ORe y for prov d ng so much he p w th wr t ng and ed tor a matters, and
espec a y h s gu dance n us ng the (not a ways good-tempered) Word temp ates
The techn ca qua ty of the book has been great y mproved by Luca Regn co , who
as tech rev ewer po nted out numerous errors and om ss ons I espec a y va ue h s nput
on the W ndows Store chapters
Kara Ebrah m at ORe y, a ong w th D anne Russe and Bob Russe at Octa Pub shng, prov ded exce ent ed tor a support and made sure everyth ng got done on t me
And ast y, Id ke to thank my fam y, who have put up w th a the extra work nvo ved n wr t ng a book, and are probab y hop ng that th s s ast one for a wh e!
Introductionxxv
Stay in touch
Lets keep the conversat on go ng! Were on Tw tter http://twitter.com/MicrosoftPress
xxviIntroduction
PAR T I
He o C++!
CHAPTER 2
13
CHAPTER 3
23
CHAPTER 4
Us ng funct ons
37
CHAPTER 5
57
CHAPTER 6
77
CHAPTER 7
103
CHAPTER 8
Inher tance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
121
CHAPTER 1
Hello C++!
After completing this chapter, you will be able to
e come to the exc t ng wor d of programm ng M crosoft NET w th M crosoft V sua C++ Th s
chapter ntroduces the C++/CLI anguage and shows you how to perform s mp e nput/output(I/O)
What is C++/CLI?
C++/CLI s a vers on of the C++ programm ng anguage des gned to run on the NET Framework
It has been ava ab e s nce M crosoft V sua Stud o 2005 and s the subject of an nternat ona standard You can find deta s of the ECMA standard at http://www.ecma-international.org/publications/
standards/Ecma-372.htm
To ach eve th s, some changes had to be made to standard C++ There are some th ngs that you
can do n standard C++ that are not perm tted n C++/CLI (for examp e, you cannot nher t from
mu t p e base c asses) and there have been some changes to the anguage geared to support NET
features (such as nterfaces and propert es) and to work w th the NET Runt me
Why wou d you choose to use C++/CLI to wr te NET code nstead of another NET anguage such
as C#? Apart from persona preference, there are two very good reasons to choose C++/CLI The first
s for nteroperab ty; C++/CLI makes t s mp e to ncorporate standard C++ code nto NET projects
The second s that we have a NET vers on of the C++ Standard Temp ate L brary (STL), and so peop e
used to cod ng aga nst the STL w find t poss b e to work n the same way n NET
Even f ne ther of these reasons app es to you, C++/CLI s st a perfect y good way to earn about
NET programm ng because t exposes a of the features that you need to wr te NET programs and
exp ore the NET p atform
The first ne (wh ch beg ns w th using) nforms the comp er that youre us ng the NET System
brary Many d fferent brar es cou d be used n a s ng e project; the using statement spec fies
to the comp er wh ch brary you want to use
The rest of the app cat on s an examp e of a C++ function A b ocks of code n C++ are
ca ed funct onstheres no such th ng as a procedure or a subrout ne Each C++ funct on
conta ns the header (the first ne of th s app cat on) and the funct on body (a of the text
between the braces, { and }) The header shows the return type of the funct on ( n th s case
int, short for integer), the name of the funct on (main), and the st of parameters ns de round
brackets Note that you st need to nc ude the round brackets even f you dont have anyth ng to pass to the funct on
A statements n C++ are term nated w th a sem co on
Of the s x nes of code n the examp e app cat on, on y two conta n C++ statements the Console
ne and the return ne The Console ne outputs characters to the conso e, and the argument to the
funct on cons sts of the str ng that you want to output The return ne ex ts from the funct on n
th s case, the app cat on, because there s on y one funct onand returns zero, wh ch s the standard
va ue to return when execut on s successfu
Identifier
ma n
NT
B4ugotxtme
dent fier1
Underscores at the beg nn ng of names are a owed, but they are not recommended because
comp ers often use ead ng underscores when creat ng nterna var ab e names, and they are
a so used for var ab es n system code. To avo d potent a nam ng confl cts, you shou d not use
ead ng underscores.
Th s w ndow s the powerfu V sua Stud o ntegrated deve opment env ronment (IDE) It conta ns
a the too s you need to create fu -featured, easy-to-use app cat ons
Note This book was written by using the Release Candidate (RC) version of Visual Studio
2012. As a result, screen shots and other details might differ from the version youre using
when you read this.
Chapter 1 He o C++! 7
Creating a project
The first task s to create a new project for the He o, Wor d program
1. In V sua Stud o, on the F e menu, po nt to New, and then c ck Project (A ternat ve y, you can
Note I am using the Professional version of Visual Studio 2012. If you are using other versions, the way in which you create a project might be different. For example, in
the Express version, you will find New Project on the File menu.
The New Project d a og box opens
2. In the nav gat on pane on the eft, under Temp ates, c ck V sua C++, and then c ck CLR In the
center pane, c ck CLR Conso e App cat on and then, toward the bottom of the d a og box, n
the Name box, type HelloWorld
Note Depending on how Visual Studio has been set up, you might find Visual C++
under the Other Languages node.
3. C ck the Locat on st and se ect a ocat on for your new project or c ck Browse and nav gate
The w zard correct y n t a zes a the comp er sett ngs for a conso e project
Not ce that the keywords automat ca y appear n b ue (prov ded that you spe them correct y)
There are a few th ngs n the automat ca y generated source code that we dont need, so ets
remove them Th s w g ve you some pract ce n us ng the ed tor as we as mak ng the code eas er to
understand The app cat on s not go ng to rece ve any command- ne arguments when you run t, so
remove everyth ng between the open ng and c os ng parentheses fo ow ng main n th s examp e,
array<System::String ^> ^args In add t on, the L before the Hello World str ng snt necessary
e ther (for reasons that I exp a n ater), so you can remove that, as we
Chapter 1 He o C++! 9
Note The shortcut keys might differ depending on the version of Visual Studio you are using. For example, in the Ultimate edition, the shortcut is F6.
An Output w ndow opens near the bottom of the V sua Stud o w ndow, show ng the bu d progress If no errors are encountered, the message Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped w
appear n the Output w ndow If th s w ndow s c osed, you can open t by se ect ng Output from the
V ew menu
If any prob ems occur, the Error L st w ndow w
You can doub e-c ck the error ne n the Error L st w ndow to p ace the cursor at the ne n the
source fi e where the comp er encountered the error F x the error (you m ght have m sspe ed a keyword or forgotten a sem co on) and rebu d the project If the Error L st pane s c osed, you can open
t by se ect ng Error L st from the V ew menu
Conclusion
A though the examp e n th s chapter snt the most exc t ng app cat on ever wr tten, t demonstrates
some key C++ deve opment po nts It ntroduces the V sua Stud o 2012 IDE and the ab ty to comp e
and nk a app cat on, and t serves as an ntroduct on to the C++/CLI anguage
Now, theres no turn ng back Every new C++/CLI and V sua Stud o 2012 feature that you earn
about w fire your mag nat on to earn more and be ncreas ng y product ve Software deve opment
s an exc t ng wor d
F na y, dont forget to have some fun Go back and try a few var at ons on the examp e app cat on,
c ck a few menus, and take some t me to become fam ar w th the env ronment
Quick reference
To
Do this
Add a fi e to a project.
Chapter 1 He o C++! 11
CHAPTER 2
Introducing object-oriented
programming
After completing this chapter, you will be able to
13
Object-or ented programm ng can crude y be character zed as dent fy ng the objects re evant
to the prob em, organ z ng them nto h erarch es, add ng attr butes to the objects to descr be the
features re evant to the prob em context, and add ng funct ons (methods) to the objects such that
they can perform the r requ red tasks The deta s are a tt e more comp cated, but essent a y, t s a
s mp e process
Yet, s mp e doesnt necessar y mean easy A co ect on of objects cou d potent a y be c ass fied n
many ways The ab ty to dent fy the mportant attr butes of objects and to form good abstract ons
and appropr ate h erarch es s cruc a Even w th n the context of a prob em doma n, ts somet mes
hard to determ ne the correct eve s of abstract on and su tab e c ass ficat on h erarch es Just dec d ng
wh ch c ass or group ng an object be ongs to can be very d fficu t As ph osopher Ludw g W ttgenste n po nted out n h s 1953 book Philosophical Investigations, some objects w bear more of a fam y
resemb ance to a concept than others; for examp e, hockey and tenn s are more obv ous y sports than
are chess and synchron zed sw mm ng
Encapsulation
One of the prob ems faced by software deve opers s that the systems we are deve op ng are becomng ncreas ng y arger and more comp ex Encapsu at on he ps to keep th ngs manageab e by breakng an app cat on down nto sma , se f-conta ned ent t es For examp e, f youre bu d ng an accountng system, you probab y need objects to represent accounts and nvo ces After youve deve oped
the Account c ass, you no onger need to worry about the deta s of the mp ementat on of the c ass
You can use the c ass anywhere n your app cat on n much the same way you wou d use a bu t- n
type, such as an nteger The c ass exposes the essent a features of the Account object wh e h d ng
the mp ementat on deta s
The accounts name and the state of ts ba ance are some of the attr butes of the object n wh ch
the c ent s nterested and needs to know Deta s of how the account name s storedwhether ts
an array of 50 characters or a str ng object, or the fact that the accounts ba ance s ma nta ned as a
currency var ab eare rre evant to the c ent The process of h d ng the data structures and mp ementat on deta s of an object from other objects n the system s ca ed encapsulation (somet mes
a so known as data hiding), and t prevents the other objects from access ng deta s about wh ch they
14Microsoft Visual C++/CLI Step by Step
dont need to know Encapsu at on makes arge programs eas er to comprehend; data h d ng makes
them more robust
Objects can nteract w th other objects through on y the r pub c y exposed attr butes and methods
The more attr butes and methods that are pub c y exposed, the more d fficu t t w be to mod fy the
c ass w thout affect ng the code that uses the c ass When done proper y, the nner work ngs of a c ass
can be changed w thout affect ng the code that uses objects created, or instantiated, from that c ass
The programmer wou d have to worry on y about the methods n the c ass that accessed that var ab e
rather than worry about a the p aces n the app cat on that an object nstant ated from that c ass
m ght be ca ed
Inheritance
The natura tendency for humans to c ass fy objects nto h erarch es s usefu from a programmers
perspect ve and s supported n object-or ented anguages, nc ud ng C++, by nher tance Inher tance prov des two benefits to the C++ programmer F rst, and most mportant, t ets you bu d
h erarch es that express the is a re at onsh ps between types Suppose that you have two c asses,
SavingsAccount and CheckingAccount, both of wh ch are der ved from the parent Account c ass If
you have a funct on that requ res an Account as an argument, you can pass t a SavingsAccount or
aCheckingAccount because both c asses are types of Account Account s a genera c ass ficat on, and
CheckingAccount and SavingsAccount are more spec fic types The second benefit of object-or ented
programm ng s that c asses can nher t features from c asses h gher n the h erarchy Instead of deve op ng new c asses from scratch, new c asses can nher t the funct ona ty of ex st ng c asses and then
mod fy or extend th s funct ona ty The parent c ass from wh ch the new c ass nher ts s known as the
base class, and the new c ass s known as the derived class
One of the major tasks fac ng deve opers s find ng appropr ate c ass ficat ons for the objects and
c asses n the r programs For examp e, f you need to deve op c asses for a dr v ng game, t makes
more sense for you to deve op a genera car c ass and then use th s c ass as a base c ass for spec fic car
types such as sportscar or truck These der ved c asses wou d then extend or mod fy the genera car
c ass by add ng new attr butes and methods or by overr d ng ex st ng methods Compos ng objects
from subobjectsfor examp e, a car cons st ng of an eng ne and a chass scan a so s mp fy the deve opment effort Do ng t th s way, each of the objects s s mp er and therefore eas er to des gn and
mp ement than the co ect ve who e
Polymorphism
The th rd feature of object-or ented programm ng anguages s polymorphism, wh ch s Greek for
many forms It s qu te a hard concept to define, so I use some examp es to show you what po ymorph sm s and eave the prec se defin t ons to more academ c wr ters
Po ymorph sm essent a y means that c asses can have the same behav or but mp ement t n
d fferent ways Cons der severa d fferent types of veh c e they a need to be started, so n programm ng terms, we cou d say that a veh c es have start funct ona ty Exact y how start ng s mp emented depends on the veh c e If t s a Ford Mode T, start ng w mean manua y crank ng the
start ng hand e at the front of the veh c e, but f t s a modern car, start ng w mean turn ng the key
n the gn t on If the veh c e s a steam ocomot ve, start ng w be a very d fferent and more comp ex
process, ndeed
As another examp e, cons der the aforement oned SavingsAccount and CheckingAccount types A
types der ved from Account share certa n funct ona ty, such as the ab ty to depos t, w thdraw, and
query the ba ance They m ght mp ement them n d fferent ways because CheckingAccount m ght
perm t an overdraft, whereas SavingsAccount m ght accrue nterest, but they a work the same way
Th s means that f Im passed an Account, t doesnt matter exact y what type of account t s; I can st
depos t funds, w thdraw funds, and query the ba ance Th s funct ona ty s usefu n programm ng
terms because t g ves you the ab ty to work w th gener c object typesaccounts and veh c es
when youre not concerned w th the way n wh ch each c ass mp ements funct ona ty
and compos t on to der ve new c asses from the ex st ng c asses The ex st ng c asses are reused as
bu d ng b ocks and not a tered n any way Creat ng systems from reusab e components natura y
eads to h gher product v ty, wh ch s probab y the most frequent y c ted benefit of object-or ented
approaches Object-or ented programm ng shou d a so resu t n h gher-qua ty systems When you
reuse c asses, t means that you are us ng code that has a ready been tested and proven n ear er
projects; thus, t s ke y to conta n fewer bugs than c asses deve oped from scratch Over t me, any
bugs that m ght have ex sted have been found and fixed n these c asses, whereas code that s wr tten
from scratch has yet to pass through the same bug detect on and fix ng process
The features (encapsu at on, nher tance, and po ymorph sm) of object-or ented programm ng a so
prov de benefits Encapsu at on makes t eas er to sca e up from sma systems to arge systems For
the most part, regard ess of the s ze of the system, the deve oper s s mp y creat ng objects Large systems m ght requ re more objects than sma systems, but the eve of comp ex ty fac ng the deve oper
s not s gn ficant y ncreased Inher tance he ps to mprove the flex b ty and extens b ty of systems,
hence reduc ng the r costs to ma nta n Der v ng new c asses from ex st ng c asses prov des add t ona
funct ona ty and makes t poss b e to extend the software w thout a ter ng the ex st ng c asses
F na y, data h d ng a so eads to more secure systems The state of an object can be mod fied on y
by ts pub c y exposed methods, wh ch ncreases the pred ctab ty of object behav or
A simple example
The fo ow ng s mp e examp e shou d serve to show you how to create a c ass, nstant ate objects, and
access member funct ons and attr butes
1. Start M crosoft V sua Stud o 2012
2. On the F e menu, po nt to New, and then c ck Project
then c ck OK
7. The fi e An ma s cpp shou d a ready be open n the ed tor If t s not, n So ut on Exp orer, n
To dec are a c ass n C++, you use the keywords ref class fo owed by a name for the c ass
Animal n th s examp eand then you st a the member var ab es and funct ons for the c ass
between open ng and c os ng braces ({ and })
So far, you have created an Animal c ass w th an int var ab e for the number of ts egs and a
String var ab e for ts name As t stands, no other app cat on or c ass w be ab e to access
these var ab es The members of a c assdata and methodsare pr vate by defau t and can
on y be accessed by methods of the c ass tse f C++ prov des three access mod fiers, public,
private, and protected, wh ch you use to spec fy the v s b ty of the var ous members of the
c ass
9. Add the keyword public fo owed by a co on ( ) on a new ne between the open ng brace and
By dec ar ng the var ab es after the keyword public, you make both of them access b e However, t s not usua y a good dea to a ow other c asses and parts of your app cat on access to
the var ab es of a c ass
As d scussed ear er n the sect on on encapsu at on, ts better to keep the mp ementat on
deta s of a c ass h dden from users of that c ass and to contro the access to the c asss data
through funct ons In the next step, we use the keyword private to prevent d rect access to the
String var ab e of the c ass We eave the int var ab e legs w th pub c access, s mp y to show
how t can then be d rect y accessed by the ma n app cat on
10. Add the keyword private fo owed by a co on ( ) between the first int var ab e and the second
String var ab e
ref class Animal
{
public:
int legs;
private:
String ^name;
};
To prov de access to the pr vate String var ab e, pub c accessor funct ons and methods need
to be added to the c ass to a ow other funct ons to man pu ate ts va ue
11. After the dec arat on of the int var ab e and before the private access mod fier, add the fo ow-
Because these methods are sma funct ons, ts eas est to dec are and mp ement them as
inline functions In ne funct ons are exp a ned further n Chapter 6, More about c asses and
objects, when we go nto c asses n greater deta
You have probab y not ced the ref keyword Th s C++/CLI keyword s mp fies the nteract on w th
NET Framework components By p ac ng ref n front of the class keyword, the c ass becomes a managed c ass When the object s nstant ated, t s created on the Common Language Runt me (CLR)
heap The fet me of an object nstant ated from the c ass s managed by the NET Frameworks garbage co ector When the object goes out of scope, the memory used by the object s garbage-co ected automat ca y ref c asses are known as reference types because the var ab e does not actua y
conta n the object; rather t s a po nter to the memory ocat on of the object, known as a handle
However, there are performance ssues to cons der when us ng reference types The memory has
to be a ocated from the managed heap, wh ch cou d force a garbage co ect on to occur In add t on,
reference types must be accessed v a the r hand es, affect ng both the s ze and speed of the comp ed
app cat on
Because of these performance ssues, the NET Framework a so supports value types Va ue types
are objects created on the stack The var ab e conta ns the object tse f rather than a hand e to the
object Hence, the var ab e doesnt have to be dereferenced to man pu ate the object, wh ch of course
mproves performance To dec are a va ue type c ass, the value keyword shou d be used nstead of
the ref keyword In th s case, the var ab es wou d have been created on the stack Instead of dec ar ng
hand es for th s c ass and then creat ng the objects on the CLR heap, the objects are dec ared n the
same way as the bu t- n C++ types, and the member var ab es are accessed by the dot operator
Now that you have wr tten the Animal c ass, your app cat on can use t just as the app cat on
wou d use a bu t- n type
1. In the main funct on, de ete the fo ow ng ne
Console::WriteLine(L"Hello World");
2. Dec are and create two Animal objects n your main funct on
Animal cat, dog;
3. Use the member funct on SetName to ass gn the names Cat and Dog to the respect ve cat and
dog objects, and set the legs var ab e for both objects to 4
cat.SetName("Cat");
cat.legs = 4;
dog.SetName("Dog");
dog.legs = 4;
To access the member var ab es and funct ons of an object, you use the dot operator ( ) You
can read th s as set the name of the cat to Cat, w th the dot operator re at ng the funct on
to the object on wh ch t s operat ng
Hav ng created a coup e of Animal objects and ass gned data to them, you are now go ng to
d sp ay that data on the screen
In case youve had any prob ems putt ng the app cat on together from the fragments n the
preced ng steps, the ent re app cat on s sted here
#include "stdafx.h"
using namespace System;
ref class Animal
{
public:
int legs;
void SetName(String ^nm)
{ name = nm; }
String^ GetName() { return name; }
private:
String ^name;
};
int main(array<System::String ^> ^args)
{
Animal cat, dog;
cat.SetName("Cat");
cat.legs = 4;
dog.SetName("Dog");
dog.legs = 4;
Console::WriteLine("Animal 1");
Console::Write("Name:
");
Console::WriteLine(cat.GetName());
Console::Write("Legs:
");
Console::WriteLine(cat.legs);
Console::WriteLine();
Console::WriteLine("Animal 2");
Console::Write("Name:
");
Console::WriteLine(dog.GetName());
Console::Write("Legs:
");
Console::WriteLine(dog.legs);
Console::WriteLine();
return 0;
}
6. If the bu d was successfu , run the app cat on by c ck ng Start W thout Debugg ng on the
Quick reference
To
Do this
Create a c ass.
CHAPTER 3
n Chapter 2 Introduc ng object-or ented programm ng, you ooked at the advantages of objector ented programm ng and deve oped a s mp e app cat on to ustrate the creat on and use of
c asses
In th s chapter, you take a c oser ook at how to create and use var ab es, the fundamenta data
types of C++, how to access and use c asses from the NET Framework, and how to create express ons
by us ng C++ operators
What is a variable?
Var ab es are ocat ons n memory where data can be temporar y stored for use by the app cat on
They have a name, a type, and a va ue The va ue of the var ab e can be changed dur ng the execut on
of the app cat on; hence, the name var ab e Before you can use a var ab e, you must dec are t you
must spec fy ts type, and you must g ve t a name The type of a var ab e defines the a owab e range
of va ues that the var ab e can ho d and the operat ons that you can perform on t
23
Declaring a variable
As I ment oned ear er, you must dec are var ab es before you can use them A s mp e dec arat on
cons sts of a type, fo owed by one or more var ab e names separated by commas and term nated by
a sem co on, as shown n the fo ow ng examp e
int primeNumber;
double x, y, z;
You can g ve each var ab e a qua fier before the type (for examp e, unsigned) You can a so p ace
an n t a zer after the var ab e name to g ve t an n t a va ue (for examp e, int i = 0) The qua fier and
the n t a zer are opt ona and are not requ red to appear n the dec arat on, but the base type and
var ab e name must be present The dec arat on s term nated by a sem co on
[qualifier] type name [initializer];
unsigned int i;
// An unsigned integer variable i, note the
// qualifier limiting the variable to
// positive numbers.
long salary = 0;
// A long variable initialized to zero.
double y;
// A double variable without qualifier or
// initializer.
A ocates enough memory to store the var ab e of that type and to assoc ate the name of the
var ab e w th that memory ocat on
Reserves the name of the var ab e to prevent t from be ng used by other var ab es w th n the
same scope
Note Scope refers to that part of the code for which a variable is visiblein other
words, where it can be used. The concept of scope is explained more in Chapter 4,
Using functions.
Ensures that the var ab e s used n a way cons stent w th ts type For examp e, f you have
dec ared a var ab e as a char, you cant store the va ue 3 7 n t
Variable naming
A C++ var ab e name can be any comb nat on of etters, numbers, and underscores, as ong as the
first character of the var ab e name s a etter or an underscore A though C++ does not p ace any restr ct ons on your cho ce of var ab e names, they shou d be mean ngfu , and you shou d be cons stent
n your nam ng convent ons to ncrease the readab ty of your code C++ s case-sens t ve Th s means
that myvariable and myVariable are two separate var ab es However, ts not a good dea to d fferent ate var ab es so e y on the bas s of case; do ng so cou d ead to confus on It wou d be easy to type a
etter n the wrong case and end up us ng a comp ete y wrong var ab e!
Note As is mentioned in Chapter 1, Hello C++!, its not a good idea to create identifiers
that begin with two underscores or an underscore followed by a capital letter (for example,
A). Microsoft uses this naming convention to specify macros and Microsoft-specific keywords, so starting your variables with these combinations could lead to name conflicts.
Th s statement creates three ntegers ca ed x, y, and z The first nteger s n t a zed to 10 and the
th rd to 11, whereas the second s not n t a zed
Assignment conversions
Ass gnment convers ons occur when var ab es on oppos te s des of an equa s gn are of d fferent types and the comp er can convert between the two types w thout any poss b e oss
of data For nstance, ass gn ng an int to a double resu ts n an ass gnment convers on because
conceptua y a the comp er has to do s to add 0 to the nteger to make the convers on
You m ght occas ona y need to force the comp er to perform a convers on that t otherw se wou dnt do For examp e, d v d ng two ntegers resu ts n an nteger resu t f you want a
float ng-po nt resu t, you can nstruct the comp er to convert one of the va ues to a doub e, as
ustrated here
double result = double(640) / 480;
int x;
float y;
double z;
x = 1;
z = x;
y = 3.56;
x = y;
// Assignment conversion from float to int
// results in loss of data.
// The integer 3 is stored in the variable x.
In th s fina case the comp er w generate the warn ng C4244 = convers on from float to
nt poss b e oss of data The reason for th s s because the ass gnment to an nteger w ose
the fract ona part, so 3 56 w be truncated to 3
// handle to a Person
// handle to an Account
Note It is in fact possible to use pointers in some circumstances in C++/CLI, but that is beyond the scope for this introductory discussion.
as
You typ ca y create an object dynam ca y and obta n a hand e to t by us ng the gcnew operator,
ustrated here
Th s code nstructs the runt me to create a new Person object, pass ng n the str ng Fred as n t a zat on data, and return a hand e to the object t has created
When you access a member of an object through a hand e, you use the po nter operator (->),
wh ch s d scussed n more deta n the fo ow ng chapters
Arrays
An array s a co ect on of data-storage ocat ons, each of wh ch ho ds the same type of data, such as
a ntegers or a doub es Arrays are very usefu when you want to represent a co ect on of va ues
(such as the number of days n each month or the names of company emp oyees) and you know how
many you need to store
Un ke c ass c C++, arrays n C++/CLI are objects that know how much data they are manag ng Th s
makes them safer than trad t ona C++ arrays because any attempt to read or wr te past the end of
the array resu ts n a run-t me error, but does not corrupt memory
Each storage ocat on s ca ed an element of the array E ements of the array are accessed by an
ndex, wh ch starts at zero and cont nues up to one ess than the array bound Why not start the ndex
from one? Th s s to preserve compat b ty w th other C-type anguages, wh ch a start array ndex ng
from zero
To dec are an array, you need to spec fy the type of tem that you are go ng to store You create
array objects dynam ca y by us ng the gcnew operator
array<int> ^arr = gcnew array<int>(10);
// Declare an array of ten integers.
int x;
arr[0] = 23;
// The first element in the array starts at offset 0
arr[9] = 21;
// The last element in the array starts at offset 9
x = arr[0];
// Use an element from the array
Constants
L ke var ab es, constants are named data-storage ocat ons However, un ke a var ab e, the va ue of
a constant cant be changed after t has been dec ared It has to be n t a zed when ts created and
cant be ass gned a new va ue ater C++ has two types of constants literal and symbolic
A tera constant s s mp y a va ue typed nto the app cat on The statements n the fo ow ng code
ass gn the tera s 40 and Dog to the respect ve var ab es noOfEmployees and name
noOfEmployees = 40;
name = "Dog";
A symbo c constant s a constant that s represented by a name You define t n exact y the
same way as a var ab e, but the qua fier must start w th the keyword const and the var ab e must be
n t a zed After dec arat on, you can use the constant name anywhere that you can use a var ab e of
that type, as shown n the fo ow ng
const unsigned long noOfFullTimeEmployees = 49;
const unsigned long noOfPartTimeEmployees = 234;
unsigned long noOfEmployees;
noOfEmployees = noOfFullTimeEmployees + noOfPartTimeEmployees;
There are a coup e of advantages to us ng symbo c constants rather than tera constants
The symbo c names make the app cat on more readab e The symbo c constant noOfFull
TimeEmployees s more mean ngfu than the tera constant 49
Its eas er to change a s ng e symbo c constant dec arat on than to find and rep ace a occurrences of a tera n a app cat on
However, us ng symbo c constants nstead of tera s can be taken too far It s not necessary to rep ace a tera s w th constants There are some constants that are ntu t ve y obv ous to everyone and
that are not go ng to change; for examp e, the number of days n a week or months n a year These
va ues can be eft as tera s w thout reduc ng the readab ty or ma nta nab ty of the code
Typedefs
A typedef s a user-defined synonym for an ex st ng type To create a synonym for a type, you use
the keyword typedef fo owed by the name of the type and the new name you are defin ng Because
typedef s a C++ statement, you a so need a c os ng sem co on
typedef unsigned int positiveNumber;
Th s typedef dec ares positiveNumber to be a synonym of unsigned int and can be used n a dec arat on nstead of the actua type name
positiveNumber one, two;
Th s ne makes t eas er to use certa n NET c asses Because String s n the System namespace, ts
fu name s System::String, but a using namespace statement such as th s makes t poss b e for you to
use the name w thout qua ficat on Th s w be exp a ned n more deta ater on
The String c ass conta ns a arge number of methods to s mp fy man pu at ng str ngs, such as Insert
and Replace
Note After you initialize a String object, it is immutable: It cant be changed after it is created. The member functions of the String class that appear to alter strings, such as Insert
and Replace, actually return a new String object, which contains the modified string. If you
need to make repeated changes to a string, you should use the StringBuilder class, adding a
using namespace statement for the System::Text namespace to simplify access.
Here the add t on operator + (p us s gn) s used to add the operands salary and bonus, and the ass gnment operator = (equa s gn) s used to store the tota n the remuneration var ab e
Assignment operators
You use an ass gnment express on to ass gn a va ue to a var ab e A express ons return a va ue when
eva uated, and the va ue of the ass gnment express on becomes the new va ue of the object on the
eft s de Th s funct ona ty makes t poss b e to ass gn the same va ue to a group of var ab es
noOfMammals = noOfDogs = noOfCats = 0;
Arithmetic operators
C++ has 12 ar thmet c operators, 5 of wh ch operate ke the standard mathemat ca operators the
add t on operator + (the p us s gn), the subtract on operator (the m nus s gn), the mu t p cat on
operator * (the aster sk), the d v s on operator / (the s ash), and the modu us operator % (the percent
s gn), wh ch returns the rema nder after d v s on
result = 4 + 2 - 3;
result = 4 * 5;
remainder = 7 % 3;
// result = 3
// result = 20
// remainder = 1
In add t on, there are a number of ar thmet c ass gnment operators, each of wh ch cons sts of the
operator and the = (equa s gn) so the add t on ass gnment operator += s a p us s gn w th an equa
s gn, and we a so have =, *=, /=, %= These operators are shorthand forms that comb ne the correspond ng mathemat ca operat on w th the ass gnment operat on So, the fo ow ng two statements
are dent ca
a = a + 5;
a += 5;
The add t on ass gnment operator s a shortcut operators; thus, there s no d fference between the
two statements In both statements, an add t on s performed, fo owed by an ass gnment The second
form s just a shorter way of express ng a frequent y used operat on
The ncrement and decrement operators are s m ar shorthand operators, but these operators on y
add or subtract 1 from the va ue of the var ab e
a++; // Adds 1 to the value of the variable a
a--; // Subtracts 1 from the value of the variable a
There are two forms of the ncrement and decrement operators the prefix form ++a or a, and
the postfix forms a++ or a A though both forms add or subtract 1, n the prefix form, the mathemat ca operat on s performed before the var ab e s used n the express on; n the postfix form, the
var ab e s ncremented or decremented after the var ab e has been used n the express on
int
a =
b =
c =
a, b,
b = c
++a;
a++;
c;
= 0;
// a = 1, b = 1
// c = 1, a = 2
In th s code fragment, the fina va ues of the var ab es are a = 2, b = 1, and c = 1 The prefix ncrement operator express on added 1 to the va ue of a before ass gn ng the va ue of the var ab e a to
the var ab e b The postfix ncrement operator express on ass gned the va ue of the var ab e a to the
var ab e c and then ncremented the va ue of the var ab e a by 1
> b
>= b
< b
<= b
== b
!= b
//
//
//
//
//
//
returns
returns
returns
returns
returns
returns
true
true
true
true
true
true
if
if
if
if
if
if
a
a
a
a
a
a
is
is
is
is
is
is
greater than
greater than
less than b.
less than or
equal to b.
not equal to
b.
or equal to b.
equal to b.
b.
A og ca operator s used to re ate two re at ona express ons C++ has three og ca operators the
AND operator && (two ampersands), the OR operator (two p pes), and the NOT operator ! (an exc amat on po nt) The AND operator re ates two express ons, both of wh ch must be true for the operator
to return a true va ue The OR operator returns true f e ther of the two express ons eva uates to true
a && b
(a > b) && (a < c)
a || b
(a > b) || (a < c)
//
//
//
//
//
//
returns
returns
is less
returns
returns
or a is
true
true
than
true
true
less
The eva uat on of a re at ona express on stops as soon as the og ca va ue of the who e express on
s determ ned, a feature known as short-circuit evaluation For examp e, the express on expr1 && expr2
s true on y f both expr1 and expr2 are true If expr1 s fa se, the fina va ue of the express on must be
fa se, and therefore, expr2 s not eva uated
The NOT operator returns the negat on of the Boo ean va ue of ts operand
!a
These operators are most often used n dec s on or oop structures, wh ch are d scussed n Chapter
5, Dec s on and oop statements
Bitwise operators
C++/CLI has s x b tw se operators the AND operator & (an ampersand), the OR operator (a vert ca bar), the exc us ve OR operator ^ (a caret), the comp ement operator ~ (a t de), the r ght-sh ft
operator >> (two r ght ang e brackets), and the eft-sh ft operator << (two eft ang e brackets) These
operators work on the nd v dua b ts of the byte and can on y be app ed to ntegra operandsthe
types char, short, int, and long The b tw se AND operator compares the b ts of two operands; f the b t
n the same pos t on for each operand s 1, the resu t ng b t s 1; f, however, e ther b t s 0 the resu tng b t s set to 0 Th s operator s often used to mask off b ts
The b tw se OR operator compares the b ts of two operands If e ther b t s 1, the correspond ng b t
of the resu t s 1, and f both b ts are 0, the correspond ng b t of the resu t s set to 0 The b tw se OR
operator s often used to turn on b ts, flags, or opt ons
The exc us ve OR operator sets the resu t b t to 1 on y f one of the operands has the correspondng b t set to 1 If the correspond ng b t of both operands s 1 or 0, the b t s set to 0
The comp ement operator reverses the b t sett ng of the operand If the b t s 1, t s set to 0; f the
b t s 0, t s set to 1
The eft-sh ft operator moves the b t pattern of ts eft operand to the eft by the number of b ts
spec fied by ts r ght operand The b ts vacated by the eft sh ft are fi ed w th zeros The r ght-sh ft
operator moves the b t pattern of ts r ght operand to the r ght by the number of b ts spec fied by ts
r ght operand If the var ab e s an uns gned data type, the vacated b ts w be fi ed w th zeros; f the
var ab e s s gned, the vacated b ts w be fi ed w th the s gn b t
int a;
a = 5;
a = a << 2;
a = 5;
a = a >> 2;
// b is true, so a is assigned 1.
// b is false, so a is assigned 2.
Type casting
C++/CLI supports the C-sty e cast operator, whereby the type to wh ch you want to convert the express on s p aced n parentheses n front of the express on; for examp e, (float) 7 It a so supports five
C++ cast operators
static cast<>
const cast<>
dynamic cast<>
safe cast<>
reinterpret cast<>
The static cast<> operator changes the data type of the var ab e, w th the type to wh ch you want
to cast be ng p aced n the ang e brackets For examp e, f an express on needs to convert an int to a
double, the number shou d be cast by us ng the static cast<double> operator Heres an examp e
int a = 10;
double b;
b = (int) a;
b = static_cast<double>(a);
You use the dynamic cast<> operator to cast objects down or across the nher tance h erarchy The
const cast<> operator works w th po nters, and references can be used to add or remove the const
qua ficat on of the var ab e The safe cast<> operator s an extens on added to C++/CLI; t performs
Quick reference
To
Do this
Use an array.
CHAPTER 4
Using functions
After completing this chapter, you will be able to:
Ca funct ons
y now, you shou d be fa r y comfortab e w th bas c C++/CLI syntax Youve seen how to dec are
var ab es, wr te statements, use operators, and perform s mp e conso e output However, as your
programs beg n to grow arger, you need to organ ze your code to cope w th the grow ng comp ex ty
In th s chapter, you earn how to d v de a C++/CLI app cat on nto funct ons F rst, you see how
to dec are funct on prototypes to ntroduce the funct ons to the comp er Next, you see how to
define funct on bod es to carry out the requ red process ng For examp e, you m ght wr te a funct on
to ca cu ate the expected growth on an nvestment or to extract the users password from a ogon
screen F na y, you see how to ca a funct on from e sewhere n your app cat on
Each funct on s usua y qu te short and d screte Its eas er to wr te an app cat on as a
ser es of funct ons than as a s ng e, ong scr pt because you can concentrate on one funct on at a t me
Its a so eas er to read and debug an app cat on that conta ns ots of sma funct ons than
one that conta ns a s ng e, ong funct on because you dont have to remember what the
ent re app cat on s do ng
Funct ons are reusab e After youve wr tten a funct on, you can ca t whenever you need
t n your app cat on, wh ch reduces cod ng effort and therefore mproves deve oper
product v ty
37
In th s examp e, the name of the funct on s DisplayWelcome The parentheses are requ red to nd cate that th s s a funct on The parentheses are empty n th s examp e, wh ch means that the funct on
doesnt take any parameters The void keyword at the beg nn ng of the funct on prototype nd cates
that the funct on doesnt return a va ue; presumab y, the funct on just d sp ays a we come message on
the screen
Note Some programming languages differentiate between functions (which return a value)
and subroutines (which do not return a value). For example, Microsoft Visual Basic .NET
uses the Function keyword for functions and the Sub keyword for subroutines. C++ only has
functions; use the void return type if the function doesnt return a value. Also, notice the
semicolon at the end of the function prototype. The semicolon is a statement terminator,
and it marks the end of the function prototype. A function prototype doesnt give you any
indication as to what the function does; it just provides the function signature.
In th s exerc se, you w dec are a s mp e funct on prototype n a C++/CLI app cat on The funct on
does not take any parameters, and t does not return a va ue, e ther
1. Start V sua Stud o 2012 and create a new CLR Conso e App cat on project named
InvestmentPlanner
After the project s created, the source fi e appears n the ed tor w ndow
38Microsoft Visual C++/CLI Step by Step
2. At the top of the fi e, mmed ate y be ow the using namespace System; ne, add the fo ow ng
funct on prototype
void DisplayWelcome();
Th s ne s the funct on prototype you saw ear er You p ace funct on prototypes near the top
of the source fi e so that they are v s b e to the rest of the code n the fi e
3. On the Bu d menu, c ck Bu d So ut on to bu d your app cat on and check that there are no
syntax errors
Theres no po nt n runn ng the app cat on yet because you havent mp emented or ca ed the
DisplayWelcome funct on You do that ater n th s chapter
1. Cont nue work ng w th the project you created n the prev ous exerc se
2. Add the fo ow ng funct on prototype mmed ate y be ow the void DisplayWelcome() ne
void DisplayProjectedValue(double amount, int years, double rate);
Th s funct on prototype dec ares a funct on named DisplayProjectedValue The funct on takes
three parameters a double, an int, and another double The comp er uses th s nformat on to
ensure that the funct on s a ways ca ed w th the correct number and types of parameters
Tip Parameter names are optional in the function prototype. Strictly speaking, you
could omit the parameter names and just specify the parameter types. However, parameter names help to convey the meaning of the parameters, so its good practice
to use them.
3. Bu d your app cat on to check the syntax
1. Cont nue work ng w th the project from the prev ous exerc se
2. Add the fo ow ng funct on prototype mmed ate y be ow the void DisplayProjectedValue() ne
double GetInvestmentAmount();
Amount() ne
int GetInvestmentPeriod(int min, int max);
Th s examp e shows how to dec are a funct on that takes parameters and returns a va ue The
GetInvestmentPeriod funct on takes two int parameters and returns an int
Note The parameter types and return type are independent of one another. The
fact that the GetInvestmentPeriod parameters and return type are all ints is entirely
coincidental. Its quite easy to imagine a function whose parameter types and return
type are different, as shown in this example:
double CalculateAverageValue(int number1, int number2);
define defau t parameters n one of the funct on prototypes you dec ared
1. Cont nue work ng w th the project from the prev ous exerc se
2. F nd the fo ow ng funct on prototype
int GetInvestmentPeriod(int min, int max);
Th s funct on prototype has two parameters named min and max The parameters are fo owed by = (the equa s gn) and then a defau t va ue We have defined a defau t va ue of 10
for the min parameter and a defau t va ue of 25 for the max parameter You see how to ca
th s funct on n the sect on Ca ng funct ons ater n th s chapter
4. Bu d your app cat on
Not ce that the first ne of the funct on body s dent ca to the funct on prototype, except that
there s no sem co on Th s first ne s known as the function header
After the funct on header, a pa r of braces ({}) enc oses the executab e statements for the funct on body In th s examp e, the DisplayWelcome funct on d sp ays a s mp e we come message on the
screen In the next two sect ons you see more comp ex funct ons that perform conso e nput and
mathemat ca ca cu at ons
The return keyword at the end of the funct on causes flow of contro to return to the ca ng funct on In th s examp e, the return keyword s superfluous because the c os ng brace of the funct on acts
as an mp c t return However, you can use return n other ocat ons n a funct on, such as w th n an if
statement, to return premature y from a funct on You see more about the if statement n Chapter 5,
Dec s on and oop statements
In th s exerc se, you w
body as fo ows
void DisplayWelcome()
{
Console::WriteLine("--------------------------------");
Console::WriteLine(
"Welcome to your friendly Investment Planner");
Console::WriteLine("---------------------------------");
return;
}
3. Bu d your app cat on You shou dnt get any comp er errors
Note You can define function bodies in any order in C++/CLI. For example, you can place
the DisplayWelcome function body before or after the main function body. However, functions cannot be nested. You cant define one function body inside the braces ({}) of another
function.
Tip The function body can use different parameter names than the prototype because the
parameter names in the prototype are there just for documentation. However, for consistency, you should use the same parameter names in the prototype and the function body.
In th s exerc se, you w define a funct on body for the DisplayProjectedValue funct on You saw the
prototype for th s funct on ear er
void DisplayProjectedValue(double amount, int years, double rate);
The funct on body w have the same s gnature as the prototype and w ca cu ate the projected
va ue of an nvestment after a spec fied number of years at a part cu ar growth rate
1. Cont nue work ng w th the project from the prev ous exerc se
2. Scro to the end of the source code and add the fo ow ng nesth s s the start of the
Here, the rateFraction var ab e ho ds the growth rate as a fract ona va ue For examp e, f the
rate s 6 percent, rateFraction w be 1 06
Note If you forget to return a value, youll get an error when the compiler reaches the closing brace of the function. This point is where the compiler realizes you havent returned a
value from the function.
In th s exerc se, you w define a funct on body for the GetInvestmentAmount funct on Here s the
prototype for the funct on, as you saw ear er
double GetInvestmentAmount();
The funct on asks the user how much money she wants to nvest It returns th s va ue as a double
data type
You w a so define a funct on body for the GetInvestmentPeriod funct on The prototype for th s
funct on s as fo ows
int GetInvestmentPeriod(int min=10, int max=25);
The funct on asks the user how ong she wants to nvest the money It returns th s va ue as an int
va ue
1. Cont nue work ng w th the project from the prev ous exerc se
2. Scro to the end of the source code and define the GetInvestmentAmount funct on body as
fo ows
double GetInvestmentAmount()
{
Console::Write("How much money do you want to invest? ");
String ^input = Console::ReadLine();
double amount = Convert::ToDouble(input);
return amount;
}
The first statement d sp ays a prompt message on the conso e, ask ng the user how much
money she wants to nvest The Console::ReadLine funct on ca reads a ne of text from the
keyboard, and the resu t s ass gned to a String var ab e
The Convert::ToDouble funct on ca parses the String and converts t to a double va ue The
return statement returns th s va ue back to the ca ng funct on
Tip You can declare local variables anywhere in a function. For example, here the
input and amount variables are declared halfway down the GetInvestmentAmount
function. Typically, you should declare variables at the point where they are first
needed in the function, which is different from the C programming language, for
which you have to declare local variables at the start of a block.
3. Add the fo ow ng funct on body
int GetInvestmentPeriod(int min, int max)
{
Console::Write("Over how many years [");
Console::Write("min=");
Console::Write(min);
Console::Write(", max=");
Console::Write(max);
Console::Write("] ? ");
String ^input = Console::ReadLine();
int years = Convert::ToInt32(input);
return years;
}
The Console::Write funct on ca s ask the user to enter a va ue between min and max These
va ues are supp ed as parameters nto the GetInvestmentPeriod funct on
The Console::ReadLine funct on ca reads the users nput as a String, and the Convert::ToInt32
funct on ca converts th s va ue nto a 32-b t nteger The return statement returns th s va ue
to the ca ng funct on
Note The function prototype for GetInvestmentPeriod declared default values for
the min and max parameters. The default value for min is 10, and the default value
for max is 25. Default values are specified only in the function prototypeyou dont
mention these default values in the function body. If you accidentally define the
default values in the function body as well as in the function prototype, youll get a
compiler error at the function body.
4. Bu d your app cat on
Calling functions
Now that you have defined a the funct on bod es n the samp e app cat on, the ast step s to ca the
funct ons at the appropr ate p ace n the app cat on
To ca a funct on, spec fy ts name fo owed by a pa r of parentheses For examp e, you can ca the
DisplayWelcome funct on as fo ows
DisplayWelcome();
Note You can ignore the return value from a function if you want. When you call the function, leave out the assignment operator on the left side of the function name. The function
still returns the value, but the value is discarded.
If you want to ca a funct on that takes parameters, pass the parameter va ues between the parentheses n the funct on ca The fo ow ng examp e ca s the DisplayProjectedValue funct on, pass ng n
three tera va ues as parameters
DisplayProjectedValue(10000, 25, 6.0);
Note You dont specify the parameter data types when you call a function. Just provide the
parameter values.
The fo ow ng examp e shows how to ca a funct on that takes parameters and returns a va ue In
th s examp e, you ca the GetInvestmentPeriod funct on to get a va ue between 5 and 25 You ass gn
the return va ue to a oca int var ab e named period
int period = GetInvestmentPeriod(5, 25);
extend your samp e app cat on to nc ude the funct on ca s youve just seen
1. Cont nue work ng w th the project from the prev ous exerc se
2. Locate the main funct on and then rep ace the ne that pr nts He o, wor d w th the fo ow-
Console::WriteLine("\nIllustration...");
DisplayProjectedValue(10000, 25, 6.0);
ong
Console::WriteLine("\nEnter details for your investment:");
double sum = GetInvestmentAmount();
int period = GetInvestmentPeriod(5, 25);
NoteThe GetInvestmentPeriod function has default values for each of its parameters. (The first parameter has a default value of 10, and the second parameter has a
default value of 25.) You can use these default values when you call the function. For
example, the following function call uses the default value for the second parameter:
int period = GetInvestmentPeriod(5);
// First parameter is 5;
// second parameter
// defaults to 25.
If you use a default value for a parameter, you must use the default values for each
subsequent parameter in the parameter list. For example, the following function call
is invalid:
int period = GetInvestmentPeriod(, 20);
6. Bu d your app cat on and fix any comp er errors On the Debug menu, c ck Start W thout
Debugg ng to run the app cat on You shou d see output s m ar to the fo ow ng
sert a debug breakpo nt A red dot appears n the border, as shown n the graph c that fo ows
Tip If you add a breakpoint in the wrong place, simply click again on the red dot to
remove it.
After the app cat on oads, t executes and stops at the breakpo nt n the main funct on
The debugger ca s the DisplayWelcome funct on and d sp ays a ye ow arrow at the start of
that funct on
Note You can also use the Debug toolbar to control the debugger. To display the
Debug toolbar, on the View menu, point to Toolbars and then click Debug from the
list of toolbars that appears. Each of the debug function keys mentioned in the remainder of this exercise has an equivalent Debug toolbar button.
6. Press F10 severa t mes to step over each statement one at a t me n the DisplayWelcome
funct on
Th s causes a we come message to be d sp ayed n the conso e w ndow At the end of the
funct on, the debugger returns you to the main funct on The ye ow arrow nd cates the next
statement to execute n main
The debugger executes the Console::WriteLine funct on but doesnt take you through t step
by step The ye ow arrow moves on to the DisplayProjectedValue funct on ca n main
8. Press F11 to step nto the DisplayProjectedValue funct on On the Debug menu, po nt to
The Loca s w ndow d sp ays five oca var ab es The first three var ab esamount, years, and
rateare the funct on parameters These var ab es are a ready n t a zed w th the va ues you
passed nto the funct on
The ast two var ab esfinalAmount and rateFractiondo not have mean ngfu va ues because the var ab es havent been ass gned a va ue yet In fact, the debugger s a tt e m s eadng here because the finalAmount and rateFraction var ab es havent even been dec ared yet
These var ab es dont rea y ex st unt the var ab e dec arat on statements further on n the
funct on
9. Press F10 severa t mes to step over the statements n the DisplayProjectedValue funct on
Observe how the finalAmount and rateFraction var ab es change dur ng the funct on (The
debugger d sp ays va ues that were changed dur ng the execut on of the prev ous statement
n red for prom nence ) Take a ook at the conso e w ndow to see what s d sp ayed
10. Keep press ng F10 unt you reach the end of the DisplayProjectedValue funct on and return to
main
funct on When the debugger executes the ReadLine statement, the conso e w ndow appears
and you are asked to enter a number Type a number such as 20 and then press Enter
13. Keep stepp ng through the GetInvestmentAmount funct on unt you return to ma n
14. Press F10 one more t me and then exam ne the oca var ab es n main Not ce that the return
va ue from GetInvestmentAmount has been ass gned to the sum oca var ab e n main
15. Cont nue stepp ng through the app cat on n th s manner unt the app cat on term nates
Tip If the debugger takes you into a function that youre not interested in stepping
through, press Shift+F11 to step out of the function. If you just want to run the application
without stopping at all, press F5.
Its a so poss b e to dec are var ab es g oba y, outs de of any funct on G oba var ab es are v s b e
n a funct on bod es that come after the g oba var ab e defin t on n your source fi e You can use
g oba var ab es as a rud mentary way of shar ng nformat on between mu t p e funct ons
Important Global variables are generally considered bad programming practice, especially in object-oriented languages such as C++. Global variables have too much visibility.
Because global variables can often be used in several functions, if one becomes corrupt,
it can be difficult to pinpoint where the problem occurred. Global variables also introduce
too much dependency between functions.
For these reasons, you should use global variables sparingly. A better way of sharing information between functions is to pass parameters and return values, as you saw earlier in this
chapter.
In th s exerc se, you w define a g oba var ab e n your app cat on You w
n severa funct ons to ustrate ts g oba scope
1. Cont nue work ng w th the project from the prev ous exerc se
2. Before the start of the main funct on, define a g oba nteger var ab e named numberOf
YourFunctionsCalled, as fo ows
int numberOfYourFunctionsCalled = 0;
3. F nd the DisplayWelcome funct on n your code At the start of th s funct on, ncrement the
Note You can click the minus sign () symbol to the left of the code to collapse a
block of code. To view a collapsed block, click the plus sign (+) to expand it again.
This can make it easier to work with code by hiding functions that are not of interest
at the moment. In the preceding screen shot, the main function has been collapsed.
4. Add a s m ar statement to the start of every funct on n your app cat on
5. Mod fy the main funct on At the end of th s funct on, just before the return statement, d sp ay
6. Bu d and run your app cat on How many of your funct ons are ca ed dur ng the app cat on?
Overloading functions
W th C++/CLI, you can prov de many funct ons w th the same name, as ong as each funct on has a
d fferent parameter st Th s process s known as function overloading Funct on over oad ng s usefu f you have severa d fferent ways of perform ng a part cu ar operat on based on d fferent nput
parameters
For examp e, you m ght want to prov de an Average funct on to find the average va ue of two
double va ues, and you m ght have another Average funct on to find the average va ue of an array of
ntegers You can define two funct ons to support these requ rements G ve each funct on the same
name, Average, to emphas ze the common purpose of these funct ons Define d fferent parameter
sts for the funct ons to d fferent ate one from another
double Average(double number1, double number2);
double Average(int array[], int arraySize);
You must st mp ement both of these funct onsthere s no mag c here! When you ca the
Average funct on, the comp er deduces wh ch vers on of the funct on to ca based on the parameter
va ues you supp y
Note If you define overloaded functions, the functions must have different parameter lists.
If you define overloaded functions that differ only in their return type, youll get a compiler
error.
In th s exerc se, you w define an over oaded vers on of the DisplayProjectedValue funct on The
new vers on ca cu ates a random growth rate between 0 and 20 percent rather than use a spec fic
growth rate
1. Cont nue work ng w th the project from the prev ous exerc se
2. Add the fo ow ng funct on prototype at the start of your code, be ow the ex st ng prototype
for DisplayProjectedValue
void DisplayProjectedValue(double amount, int years);
3. In the main funct on, ocate the second ca to the DisplayProjectedValue funct on Mod fy the
DisplayProjectedValue funct on
void DisplayProjectedValue(double amount, int years)
{
numberOfYourFunctionsCalled++;
Random r;
int randomRate = r.Next(0, 20);
DisplayProjectedValue(amount, years, randomRate);
}
Tip You now have two overloaded DisplayProjectedValue functions. It is good practice to keep overloaded functions together in the source code.
Th s funct on uses the Random c ass to ca cu ate a random number between 0 and 20 The
funct on passes the random number nto the or g na vers on of the DisplayProjectedValue
funct on to ca cu ate the va ue of the nvestment us ng th s random rate
5. Define breakpo nts at the start of both of the DisplayProjectedValue funct ons
6. Bu d the app cat on and start t n the debugger
7. Observe wh ch vers ons of DisplayProjectedValue are ca ed as your app cat on executes See
what random number the app cat on uses for your growth rate
8. Run the app cat on severa t mes to ver fy that the growth rate rea y s random
Quick reference
To
Do this
Ca a funct on.
CHAPTER 5
be ab e to
Perform uncond t ona jumps n a oop by us ng the break and continue statements
h gh- eve anguages prov de keywords w th wh ch you can make dec s ons and perform oops
C++ s no except on C++ prov des the if statement and the switch statement for mak ng dec s ons, and t prov des the while, for, and do-while statements for perform ng oops In add t on, C++
prov des the break statement to ex t a oop mmed ate y and the continue statement to return to the
start of the oop for the next terat on
In th s chapter, you w
C++/CLI app cat on
see how to use these statements to contro the flow of execut on through a
The if keyword s fo owed by a cond t ona express on, wh ch must be enc osed n parentheses If
the cond t ona express on eva uates to true, the next statement s executed, wh ch n th s examp e
w d sp ay the message The number s negat ve Not ce that the message The end w a ways be
d sp ayed, regard ess of the outcome of the test, because t s outs de the body of the if statement
57
Note There is no semicolon after the closing parenthesis in the if test. It is a common C++
programming error to put one in by mistake, as shown here:
if (number < 0);
This statement is equivalent to the following statement, which is probably not what you
intended:
if (number < 0)
;
// Null if-body do nothing if number < 0
If you want to include more than one statement in the if body, enclose the if body in braces
({}), as follows:
if (number < 0)
{
Console::Write("The number ");
Console::Write(number);
Console::WriteLine(" is negative");
}
Console::WriteLine("The end");
Many developers reckon that it is good practice to enclose the if body in braces, even if it
only consists of a single statement. This means that the code will still be correct if you (or
another developer) add more statements to the if body in the future.
In th s exerc se, you w create a new app cat on to perform one-way tests As th s chapter progresses, you w extend the app cat on to use more comp ex dec s on-mak ng constructs and to
perform oops For now, the app cat on asks the user to enter a date and then t performs s mp e
va dat on and d sp ays the date n a user-fr end y format on the conso e
1. Start V sua Stud o 2012 and create a new CLR Conso e App cat on project Name the app ca-
t on CalendarAssistant
2. At the top of the source code fi e, mmed ate y be ow the using namespace System; ne, add
int GetYear();
int GetMonth();
int GetDay(int year, int month);
void DisplayDate(int year, int month, int day);
3. At the end of the fi e, after the end of the main funct on, mp ement the GetYear funct on as
fo ows
int GetYear()
{
Console::Write("Year? ");
String ^input = Console::ReadLine();
int year = Convert::ToInt32(input);
return year;
}
Later, you w enhance th s funct on to ensure that the user enters a va d day for the g ven
year and month
6. Imp ement the DisplayDate funct on as shown n the fo ow ng code to d sp ay the date as
three numbers
void DisplayDate(int year, int month, int day)
{
Console::WriteLine("\nThis is the date you entered:");
Console::Write(year);
Console::Write("-");
Console::Write(month);
Console::Write("-");
Console::Write(day);
Console::WriteLine();
}
7. Add the fo ow ng code ns de the main method, mmed ate y before the return 0; L ne
Console::WriteLine("Welcome to your calendar assistant");
Console::WriteLine("\nPlease enter a date");
int year = GetYear();
int month = GetMonth();
int day = GetDay(year, month);
Th s code asks the user to enter a year, month, and day If the date passes a s mp fied va dat on test, the date s d sp ayed on the conso e If the date s nva d, t s not d sp ayed at a
NoteThis if statement combines several tests by using the logical AND operator &&.
As you learned in Chapter 3, Variables and operators, logical tests are performed
from left to right. Testing stops as soon as the final outcome has been established.
For example, if the month is 0, there is no point performing the other teststhe
date is definitely invalid. This is known as short-circuit evaluation.
8. Bu d the app cat on and fix any comp er errors that you m ght have
9. Run the app cat on Type n va d numbers for the year, month, and day (for examp e, 2012, 7,
and 22)
The app cat on d sp ays the messages shown n the fo ow ng screen shot
Observe that the app cat on d sp ays the date because t s va d The message The End a so
appears at the end of the program
10. Run the app cat on aga n, but th s t me, type an nva d date (for examp e, 2012, 2, and 33)
The app cat on d sp ays the messages shown n the fo ow ng screen shot
Not ce that because the date you typed was nva d, the app cat on doesnt d sp ay t Instead,
t just d sp ays The End You can make the app cat on more user-fr end y by d sp ay ng an
error message f the date s nva d To do so, you need to use a two-way test
The else body defines what act on to perform f the test cond t on fa s
In th s exerc se, you w enhance your Ca endar Ass stant app cat on to d sp ay an error message f
an nva d date s entered
1. Cont nue work ng w th the project from the prev ous exerc se
2. Mod fy the main funct on, rep ac ng the s mp e if w th an if-else statement to test for va d or
nva d dates
if (month >= 1 && month <= 12 && day >= 1 && day <= 31)
{
DisplayDate(year, month, day);
}
else
{
Console::WriteLine("Invalid date");
}
Console::WriteLine("\nThe end\n");
3. Bu d and run the app cat on Type an nva d date such as 2001, 0, and 31
The app cat on now d sp ays an error message, as demonstrated n the fo ow ng screen shot
Th s code spec fies that f the month s Apr , June, September, or November, set maxDay to 30 If
the month s February, maxDay s set to 28 (We gnore eap years for now!) If the month s anyth ng
e se, set maxDay to 31
Note There is a space between the keywords else and if because they are distinct keywords. This is unlike Microsoft Visual Basic .NET, which uses the single keyword ElseIf.
In th s exerc se, you w enhance your Ca endar Ass stant app cat on to d sp ay the max mum number of days n the users chosen month
62Microsoft Visual C++/CLI Step by Step
1. Cont nue work ng w th the project from the prev ous exerc se
2. Rep ace the GetDay funct on w th the fo ow ng code so that t uses an if-else-if statement to
3. Bu d and run the app cat on Type the year 2012 and the month 1
The app cat on prompts you to enter a day between 1 and 31, as
screen shot
ustrated n the fo ow ng
4. Type a va d day and c ose the conso e w ndow when the date s d sp ayed
5. Run the app cat on aga n Type the year 2012 and the month 2
The app cat on prompts you to enter a day between 1 and 28, as shown here
6. Type a va d day and c ose the conso e w ndow when the date s d sp ayed (Dont worry about
the date va dat on n main: You w remove t ater and rep ace t w th more comprehens ve
va dat on n the GetMonth and GetDay funct ons )
If the month s February, you define a bool var ab e to determ ne f the year s a eap year A year
s a eap year f t s even y d v s b e by 4 but not even y d v s b e by 100 (except years that are even y
d v s b e by 400, wh ch are eap years) The fo ow ng tab e shows some examp es of eap years and
non eap years
64Microsoft Visual C++/CLI Step by Step
Year
Leap year?
1996
Yes
1997
No
1900
No
2000
Yes
You then use a nested if statement to test the bool var ab e isLeapYear so that you can ass gn an appropr ate va ue to maxDay
Note There is no explicit test in the nested if statement. The condition if (isLeapYear) is
equivalent to if (isLeapYear ! false).
In th s exerc se, you w
years
enhance your Ca endar Ass stant app cat on to dea correct y w th eap
1. Cont nue work ng w th the project from the prev ous exerc se
2. Mod fy the GetDay funct on, rep ac ng the ifelse ifelse statements to match the b ock of
you to enter a day between 1 and 29 Type a va d day and then when the date s d sp ayed,
c ose the conso e w ndow
4. Run the app cat on aga n Type the year 1997 and the month 2 Ver fy that the app cat on
int numberOfSides;
// Number of sides in a shape
...
switch (numberOfSides)
{
case 3: Console::Write("Triangle");
break;
case 4: Console::Write("Quadrilateral"); break;
case 5: Console::Write("Pentagon");
break;
case 6: Console::Write("Hexagon");
break;
case 7: Console::Write("Septagon");
break;
case 8: Console::Write("Octagon");
break;
case 9: Console::Write("Nonagon");
break;
case 10: Console::Write("Decagon");
break;
default: Console::Write("Polygon");
break;
}
The switch keyword s fo owed by an express on n parentheses Th s express on must eva uate to
an nteger, a character, or an enumerat on va ue The body of the sw tch cons sts of a ser es of case
branches, each of wh ch compr ses the keyword case, a va ue, and a co on
The va ue dent fy ng a case branch must be a constant of nteger type Th s means that nteger
numbers, enumerat on va ues, and characters are a owed For examp e, 5 and a are va d, but abc s
not because t s a str ng tera
Note Each case label specifies a single literal value. You cant specify multiple values, you
cant define a range of values, and the values must be known at compile time. This means
that you cant, for instance, say case foo, where foo is a variable whose value will only be
known when the application executes.
Each case branch can conta n any number of statements At the end of each branch, use a break
statement to ex t the switch statement
Note There is normally no need to use braces around the code in a case branch. The break
statement marks the end of each case branch. However, you do need to use braces if you
need to declare a variable within the branch code.
You can define an opt ona default branch n the switch statement The default branch w
ecuted f the express on doesnt match any of the case abe s
be ex-
Tip Its good practice to define a default branch even if you dont have any specific processing to perform. Including the default branch shows that you havent just forgotten it.
Also, the default branch can help you trap unexpected values and display a suitable warning to the user.
In th s exerc se, you w enhance your Ca endar Ass stant app cat on to d sp ay the month as a
str ng such as January or February
66Microsoft Visual C++/CLI Step by Step
1. Cont nue work ng w th the project from the prev ous exerc se
2. Mod fy the DisplayDate funct on Rather than d sp ay the month as an nteger, rep ace the
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
Console::Write("Consonant"); break;
There s no break statement n the first four case abe s As a resu t, the flow of contro passes on
to the next executab e statement to d sp ay the message Vowel The default branch dea s w th a the
other etters and d sp ays the message Consonant
enhance your Ca endar Ass stant app cat on to d sp ay the season for the
1. Cont nue work ng w th the project from the prev ous exerc se
2. Mod fy the DisplayDate funct on After d sp ay ng the year, month, and day, add the fo ow ng
case 6:
case 7:
case 8:
case 9:
case 10:
case 11: Console::WriteLine(" [Fall]"); break;
}
Performing loops
For the rest of th s chapter, you see how to perform oops n C++/CLI You a so see how to perform
uncond t ona jumps n a oop by us ng the break and continue statements
C++ has three ma n oop constructs the while oop, the for oop, and the do-while oop
Note There is actually a fourth loop type, the for-each loop, but Ill leave discussing that
until we get to arrays.
Lets ook at the while oop first
int count = 1;
while (count <= 5)
{
Console::WriteLine(count * count);
count++;
}
Console::WriteLine("The end");
You must fo ow the while keyword w th a cond t ona express on enc osed n parentheses As ong
as the cond t ona express on eva uates to true, the while body executes After the oop body has been
executed, contro returns to the while statement and the cond t ona express on s tested aga n Th s
sequence cont nues unt the test eva uates to fa se
You must, of course, remember to nc ude some k nd of update statement n the oop so that t w
term nate eventua y In th s examp e count++ s ncrement ng the oop counter If you dont prov de
an update statement, the oop w terate forever, wh ch probab y snt what you want
The preced ng examp e d sp ays the fo ow ng output
enhance your Ca endar Ass stant app cat on so that the user can type five
1. Cont nue work ng w th the project from the prev ous exerc se
2. Mod fy the code n the main funct on by rep ac ng the ent re body of the funct on w th the
fo ow ng code
Console::WriteLine("Welcome to your calendar assistant");
int count = 1;
// Declare and initialize the loop counter
while (count <= 5)
// Test the loop counter
{
Console::Write("\nPlease enter a date ");
Console::WriteLine(count);
int year = GetYear();
int month = GetMonth();
int day = GetDay(year, month);
DisplayDate(year, month, day);
count++;
3. Bu d and run the app cat on The app cat on prompts you to enter the first date After you
have typed th s date, the app cat on prompts you to enter the second date Th s process cont nues unt you have typed five dates, at wh ch po nt the app cat on c oses, as dep cted n the
fo ow ng screen shot
The parentheses after the for keyword conta n three express ons separated by sem co ons The first
express on performs oop n t a zat on, such as n t a z ng the oop counter Th s n t a zat on express on s executed once on y, at the start of the oop
Note You can declare loop variables in the first expression of the for statement. The preceding example illustrates this technique. The count variable is local to the for statement
and goes out of scope when the loop terminates.
The second express on statement defines a test If the test eva uates to true, the oop body s
executed, but f t s false, the oop fin shes and contro passes to the statement that fo ows the c osng parenthes s After the oop body has been executed, the fina express on n the for statement s
executed; th s express on performs oop update operat ons, such as ncrement ng the oop counter
70Microsoft Visual C++/CLI Step by Step
NoteThe for statement is very flexible. You can omit any of the three expressions in the
for construct as long as you retain the semicolon separators. You can even omit all three
expressions, as in for( ; ; ), which represents an infinite loop
The preced ng examp e d sp ays the output shown n the fo ow ng screen shot
In th s exerc se, you w mod fy your Ca endar Ass stant app cat on so that t uses a for oop rather
than a while oop to obta n five dates from the user
1. Cont nue work ng w th the project from the prev ous exerc se
2. Mod fy the code n the main funct on to use a for oop rather than a while oop, as shown
here
Console::WriteLine("Welcome to your calendar assistant");
for (int count = 1; count <= 5; count++)
{
Console::Write("\nPlease enter date ");
Console::WriteLine(count);
int year = GetYear();
int month = GetMonth();
int day = GetDay(year, month);
DisplayDate(year, month, day);
}
Not ce that there s no count++ statement after d sp ay ng the date Th s s because the for
statement takes care of ncrement ng the oop counter
3. Bu d and run the app cat on The app cat on asks you to enter five dates, as before
The fo ow ng examp e shows how to wr te a s mp e do-while oop n C++/CLI Th s examp e generates random numbers between 1 and 6, nc us ve, to s mu ate a d e It then counts how many throws
are needed to get a 6
Random ^r = gcnew Random();
int randomNumber;
int throws = 0;
do
{
randomNumber = r->Next(1, 7);
Console::WriteLine(randomNumber);
throws++;
}
while (randomNumber != 6);
Console::Write("You took ");
Console::Write(throws);
Console::WriteLine(" tries to get a 6");
The oop starts w th the do keyword, fo owed by the oop body, fo owed by the while keyword
and the test cond t on A sem co on s requ red after the c os ng parenthes s of the test cond t on
The preced ng examp e d sp ays the output shown n the fo ow ng screen shot
In th s exerc se, you w mod fy your Ca endar Ass stant app cat on so that t performs nput va dat on, wh ch s a typ ca use of the do-while oop
1. Cont nue work ng w th the project from the prev ous exerc se
2. Mod fy the GetMonth funct on as fo ows, wh ch forces the user to type a va d month
int GetMonth()
{
int month = 0;
do
{
Console::Write("Month [1 to 12]? ");
String ^input = Console::ReadLine();
month = Convert::ToInt32(input);
}
3. Mod fy the GetDay funct on as fo ows, wh ch forces the user to type a va d day
int GetDay(int year, int month)
{
int day = 0;
int maxDay;
// Calculate maxDay, as before (code not shown here)
do
{
Console::Write("Day [1 to ");
Console::Write(maxDay);
Console::Write("]? ");
String ^input = Console::ReadLine();
day = Convert::ToInt32(input);
}
while (day < 1 || day > maxDay);
return day;
}
NoteThe break and continue statements can make it difficult to understand the logical
flow through a loop. Use break and continue sparingly to avoid complicating your code
unnecessarily.
In th s exerc se, you w mod fy the ma n oop n your Ca endar Ass stant app cat on You w g ve
the user the chance to break from the oop premature y, sk p the current date and cont nue on to the
next one, or d sp ay the current date as norma
1. Cont nue work ng w th the project from the prev ous exerc se
2. Mod fy the main funct on as fo ows, wh ch g ves the user the opt on to break or continue f
des red
Console::WriteLine("Welcome to your calendar assistant");
for (int count = 1; count <= 5; count++)
{
Console::Write("\nPlease enter date ");
Console::WriteLine(count);
int year = GetYear();
int month = GetMonth();
int day = GetDay(year, month);
Console::Write("Press B (break), C (continue), or ");
Console::Write("anything else to display date ");
String ^input = Console::ReadLine();
if (input->Equals("B"))
{
break;
}
else if (input->Equals("C"))
{
continue;
}
DisplayDate(year, month, day);
}
NoteThe Equals method is used here to check that two strings contain the same
content. You will see another (and more idiomatic) way to do this using the
operator when we discuss operator overloading.
3. Bu d and run the app cat on
4. After you type the first date, you are asked whether you want to break or cont nue Press X (or
any other key except B or C) and then press Enter to d sp ay the date as norma
5. Type the second date, and then press C fo owed by Enter, wh ch causes the continue state-
ment to be executed
The continue statement abandons the current terat on w thout d sp ay ng your date Instead,
you are asked to type the th rd date
6. Type the th rd date and then press B, wh ch causes the break statement to be executed The
Quick reference
To
Do this
switch (dayNumber)
{
case 0:
case 6:
Console::Write("Weekend");
break;
default:
Console::Write("Weekday");
break;
}
CHAPTER 6
Create objects
hapter 2, Introduc ng object-or ented programm ng, d scusses how C++ s an object-or ented
programm ng anguage Reca from that chapter that you define c asses to represent the mportant types of ent t es n your app cat on, and you create objects as nstances of these c asses For
examp e, a Human Resources app cat on m ght define c asses such as Employee and Contract When
the app cat on s runn ng, t m ght create a new Employee object every t me a new emp oyee jo ns the
company and a new Contract object to descr be the emp oyees terms of emp oyment
Th s chapter bu ds on the ntroduct on to c asses and objects n Chapter 2 In th s chapter, you
see how to organ ze c asses nto header fi es and source fi es, wh ch makes t poss b e for you to keep
a c ean separat on between a c ass defin t on and ts mp ementat on You a so earn how to prov de
constructors to n t a ze new objects when theyre created
Most of the data members and member funct ons n a c ass are instance members because they
be ong to spec fic nstances of the c ass Its a so poss b e to define class members, wh ch be ong
to the c ass as a who e You see how to define c ass members n th s chapter by us ng the static
keyword
F na y, you see how to create object re at onsh ps n C++ Th s concept s mportant n objector ented programm ng because t fac tates objects commun cat ng w th one another n a runn ng
app cat on
77
The CreditCardAccount c ass conta ns a s ng e member funct on named PrintStatement Th s funct on has been dec ared pub c, so t can be accessed by other parts of the app cat on The c ass a so
conta ns a s ng e data member named currentBalance, wh ch has been dec ared pr vate to preserve
encapsu at on
Not ce that the c ass defin t on conta ns the fu body of the PrintStatement funct on not just ts
prototype Th s s known as an inline function In ne funct ons are fine for sma funct ons but can
carry an overhead f used too much, and they can a so make the c ass defin t on hard to understand
Imag ne a c ass conta n ng 100 funct ons, a of wh ch are dec ared n ne The c ass defin t on wou d
be very ong, and t m ght be d fficu t to understand the structure of the code A common so ut on
n C++ s to d v de the c ass defin t on nto two parts a header fi e and a source fi e, as shown n the
fo ow ng figure
Note You can use any file names you like for the header file and source file. Most developers use the same name as the class, with the standard file extensions .h (for the header file)
and .cpp (for the source file.)
The header fi e, Cred tCardAccount h, conta ns the class declaration Not ce that the c ass dec arat on now conta ns function prototypes rather than funct on bod es These prototypes make the header
fi e eas er to read because the funct on s gnatures are more prom nent
The source fi e, Cred tCardAccount cpp, conta ns the class definition, wh ch cons sts of a the funct on bod es for the c ass Each funct on must be prefixed by the name of the c ass to wh ch t be ongs,
fo owed by two co ons, as fo ows
void CreditCardAccount::PrintStatement()
{
... function body ...
}
The doub e-co on syntax ( ) s the C++ scope resolution operator In th s examp e, the scope reso ut on operator te s us that the PrintStatement funct on be ongs to the CreditCardAccount c ass
The reason for th s shou d be c ear How s the comp er to know that th s s the PrintStatement
funct on that s part of CreditCardAccount as opposed to some other PrintStatement funct on?
Note You must provide an #include statement at the start of the source file to include the
header file for the class. For example, CreditCardAccount.cpp has an #include statement
to include CreditCardAccount.h. The compiler needs the information in this header file to
compile the function bodies in the source file, for example, to check that the spelling and
number of arguments in PrintStatement matches the declaration.
CreditOrganizer
2. On the Project menu, c ck Add New Item
3. In the Add New Item d a og box, n the pane on the eft, se ect V sua C++ and then, n the
c ck Add
V sua Stud o creates an empty header fi e
Every cred t card account has a un que account number, a current ba ance, and a cred t m t
The SetCreditLimit member funct on w be used to n t a ze the cred t m t for the account
You can use the MakePurchase member funct on to make a purchase on the cred t card Th s
funct on returns true f the purchase s a owed, or fa se f the purchase wou d cause the cred t
m t to be exceeded The MakeRepayment member funct on repays some or a of the outstand ng ba ance The PrintStatement member funct on d sp ays a statement for the account
And fina y, the GetAccountNumber member funct on returns the number for the account
6. Bu d the app cat on and fix any comp er errors
then c ck Add
V sua Stud o creates an empty source fi e
5. Add two #include statements at the beg nn ng of the fi e, as fo ows
#include "stdafx.h"
#include "CreditCardAccount.h"
The fi e stdafx h s a header fi e that can nc ude other standard header fi es; you nc ude
stdafx h at the start of every source fi e n your project
Cred tCardAccount h conta ns the c ass defin t on for CreditCardAccount You nc ude th s
header fi e here so that the comp er can check your mp ementat on of the CreditCardAccount
c ass
6. Add the fo ow ng code so that you can use c asses and data types defined n the System
namespace
#using <mscorlib.dll>
using namespace System;
The #using <mscorlib.dll> preprocessor d rect ve mports the M crosoft Intermed ate Language (MSIL) fi e mscor b d so that you can use managed data and managed constructs
defined n th s brary fi e
The using namespace System statement he ps you to use c asses and data types defined n
the System namespace Spec fica y, you w use the Console c ass to d sp ay messages on the
conso e
7. Imp ement the CreditCardAccount::SetCreditLimit member funct on, as shown here
void CreditCardAccount::SetCreditLimit(double amount)
{
creditLimit = amount;
}
Th s funct on s ca ed when the card owner attempts to make a purchase by us ng the cred t
card The amount parameter nd cates the amount of the purchase The funct on tests whether
the purchase wou d exceed the creditLimit data member, return ng false f t wou d Otherw se,
the funct on adds the amount to the currentBalance data member and returns true
Note Member functions have unrestricted access to all the members in the class,
including private members.
9. Imp ement the CreditCardAccount::MakeRepayment member funct on as fo ows
void CreditCardAccount::MakeRepayment(double amount)
{
currentBalance -= amount;
}
Th s funct on g ves the user the opportun ty to pay off some or a of the outstand ng ba ance
10. Imp ement the CreditCardAccount::PrintStatement member funct on as fo ows
void CreditCardAccount::PrintStatement()
{
Console::Write("Current balance: ");
Console::WriteLine(currentBalance);
}
Creating objects
After you have defined and mp emented a c ass, you are ready to beg n creat ng objects
The fo ow ng code shows how to create an object and ca
CreditCardAccount ^myAccount;
myAccount = gcnew CreditCardAccount;
myAccount->MakePurchase(100);
//
//
//
//
//
Declare a handle
Create a new
CreditCardAccount object
Use the -> operator to invoke
member functions
myAccount->MakeRepayment(70);
myAccount->PrintStatement();
...
The gcnew operator creates a new object of the CreditCardAccount c ass and returns a hand e to
th s new object The hand e s used w th the -> operator to nvoke member funct ons on the new
object
Note If you forget to delete an object of a managed class, the garbage collector is responsible for disposing of it. In Chapter 7, Controlling object lifetimes, you can see how this
works as well as how you can work with the garbage collector to ensure that your objects
are tidied up correctly at the end of their lives.
In th s exerc se, you w create a new CreditCardAccount object, nvoke ts member funct ons, and
de ete the object when t s no onger requ red
1. Cont nue us ng the project from the prev ous exerc se
2. If the fi e Cred tOrgan zer cpp s not v s b e n the ed tor w ndow, find the fi e n the So ut on
Exp orer, and then doub e-c ck the name to d sp ay t n the ed tor
3. Just after the #include stdafx.h ne, add another #include d rect ve as fo ows
#include "CreditCardAccount.h"
Th s ne makes t poss b e for you to create and use CreditCardAccount objects n th s source
fi e
Rep ace the body of the main funct on w th the fo ow ng code
CreditCardAccount ^myAccount;
// Declare a handle
myAccount = gcnew CreditCardAccount; // Create a new CreditCardAccount object
myAccount->SetCreditLimit(1000);
myAccount->MakePurchase(1000);
// Use the -> operator to invoke member functions
myAccount->MakeRepayment(700);
myAccount->PrintStatement();
long num = myAccount->GetAccountNumber();
Console::Write("Account number: ");
Console::WriteLine(num);
The app cat on creates a CreditCardAccount object, makes a purchase and a repayment, and
pr nts a statement However, the account number d sp ays as zero, as ustrated n the fo owng screen shot
The reason for th s s because the members of the CreditCardAccount object are n t a zed to zero
when ts created However, t doesnt rea y make sense to have an account w thout a number, so wed
ke to ensure that every account s created w th an account number
You do th s by defin ng a constructor n the CreditCardAccount c ass The constructor s a member
funct on that n t a zes new objects when theyre created Chapter 7 shows you how to t dy up objects
just before they are destroyed
Defining constructors
A constructor s a spec a member funct on that s ca ed automat ca y when an object s created The
purpose of the constructor s to n t a ze the object to br ng t nto an operat ona state You dec are
the prototype for the constructor n the c ass defin t on The fo ow ng examp e dec ares a s mp e
constructor for the CreditCardAccount c ass
ref class CreditCardAccount
{
public:
CreditCardAccount();
// ... Other members, as before
};
There are severa mportant po nts to not ce here F rst, a constructor must have the same name as
the c ass; th s s how the comp er recogn zes t as a constructor A so, a constructor cannot spec fy a
return typenot even void If you do spec fy a return type for a constructor, you w get a comp er
error
You can mp ement the constructor n the source fi e as fo ows
CreditCardAccount::CreditCardAccount()
{
accountNumber = 1234;
currentBalance = 0;
creditLimit = 3000;
}
Note Although this example has set all three fields, the compiler will arrange for fields
to be set to a default value. This is zero for numeric types, false for Booleans, and a null
value for handles.
Th s s mp e constructor n t a zes every new CreditCardAccount object w th the same va ues A
more rea st c approach s to define a constructor that takes parameters so that each object can be
n t a zed w th d fferent va ues
Note You can provide any number of constructors in a class, as long as each constructor
has a distinct parameter list. This is an example of function overloading.
In th s exerc se, you w add a constructor to the CreditCardAccount c ass The constructor takes
two parameters spec fy ng the account number and cred t m t for the new account The current ba ance s a ways n t a zed to 0 for each new account, so there s no need to supp y a parameter for th s
data member
1. Cont nue us ng the project from the prev ous exerc se
2. Open Cred tCardAccount h and dec are a pub c constructor as fo ows
ref class CreditCardAccount
{
public:
CreditCardAccount(long number, double limit);
// ... Other members, as before
};
Tip Ensure that the constructor is public. If you make it private by mistake, you
wont be able to create CreditCardAccount objects in your application.
4. Open Cred tOrgan zer cpp and mod fy the statement that creates the CreditCardAccount
object as fo ows
myAccount = gcnew CreditCardAccount(12345, 2500);
Th s statement creates a new CreditCardAccount object and passes the va ues 12345 and 2500
nto the CreditCardAccount constructor The constructor uses these parameter va ues to n t a ze the accountNumber and creditLimit data members, respect ve y
5. Bu d the app cat on, fix any comp er errors, and then run the app cat on
The app cat on now d sp ays mean ngfu nformat on for the account number, as demonstrated n the fo ow ng screen shot
W th C++, you can a so define c ass-w de members that og ca y be ong to the ent re c ass rather
than to a spec fic nstance For examp e, you can define a c ass-w de data member named interestRate
that ho ds the nterest rate for a accounts S m ar y, you can prov de c ass-w de member funct ons
ca ed SetInterestRate and GetInterestRate to work w th the nterest rate, as shown n the fo ow ng
figure
Lets see how to define c ass-w de data members and member funct ons
Th s dec arat on nforms the comp er that there s a c ass-w de data member named numberOf
Accounts and n t a zes t to zero
Note Like any other member of a class, if you do not initialize numberOfAccounts explicitly,
the default initial value will be 0.
In th s exerc se, you w add a stat c numberOfAccounts data member to the CreditCardAccount
c ass You w ncrement th s data member every t me a new CreditCardAccount object s created
1. Cont nue us ng the project from the prev ous exerc se
2. Open Cred tCardAccount h and dec are the stat c numberOfAccounts data member as fo ows
class CreditCardAccount
{
private:
3. Open Cred tCardAccount cpp and mod fy the CreditCardAccount constructor so that t ncre-
4. Open Cred tOrgan zer cpp and mod fy the ma n funct on so that t creates and uses severa
CreditCardAccount objects
Console::WriteLine("Creating first object");
CreditCardAccount ^account1;
account1 = gcnew CreditCardAccount(12345, 2000);
account1->MakePurchase(300);
account1->PrintStatement();
Console::WriteLine("\nCreating second object");
CreditCardAccount ^account2;
account2 = gcnew CreditCardAccount(67890, 5000);
account2->MakePurchase(750);
account2->PrintStatement();
5. Bu d the app cat on, fix any comp er errors, and then run the app cat on
Every t me a new CreditCardAccount object s created, the app cat on ncrements numberOf
Accounts and d sp ays ts atest va ue
Imp ement the funct on n the source fi e to match the code sn ppet that fo ows Keep n m nd that
you dont use the static keyword on the mp ementat on, but on y on the dec arat on ns de the c ass
defin t on
int CreditCardAccount::GetNumberOfAccounts()
{
return numberOfAccounts;
}
Note Because it is not associated with an instance but with the class as a whole, a static
member function can only access static class members. For example, GetNumberOfAccounts
can access numberOfAccounts, but it cannot access accountNumber, currentBalance, or
creditLimit, because they are part of an instance.
To ca a stat c member funct on, use the c ass name rather than a part cu ar nstance, as shown n
th s examp e
int n = CreditCardAccount::GetNumberOfAccounts();
The use of the c ass name emphas zes the fact that GetNumberOfAccounts s a c ass-w de member
funct on rather than an nstance member funct on
Note You have seen the syntax ClassName::FunctionName before. Every time you display a
message on the console, you use a statement such as Console::WriteLine(Hello world). This
statement calls the static member function WriteLine on the Console class.
In th s exerc se, you w define a stat c GetNumberOfAccounts member funct on n the Credit
CardAccount c ass You w then ca th s funct on severa t mes n main
1. Cont nue us ng the project from the prev ous exerc se
2. Open Cred tCardAccount h and dec are the GetNumberOfAccounts funct on as fo ows
3. Open Cred tCardAccount cpp and mp ement the GetNumberOfAccounts funct on as fo ows
int CreditCardAccount::GetNumberOfAccounts()
{
return numberOfAccounts;
}
4. Open Cred tOrgan zer cpp and mod fy the ma n funct on so that t ca s GetNumberOf
5. Bu d the app cat on, fix any comp er errors, and then run the app cat on
The app cat on d sp ays the messages dep cted n the fo ow ng screen shot
Class constructors
Suppose that you have a c ass-w de member but you cannot g ve t a va ue unt run t me For examp e, you want to set the nterest rate for the CreditCardAccount c ass to the current rate at the t me
the app cat on starts
Un ke standard C++, C++/CLI embod es the concept of a static constructor An ord nary constructor s used to n t a ze nstance members when an object s created; a stat c constructor s used to do
once-only initialization for a c ass You use them to do any setup that s needed before your c ass s
used, and t s guaranteed to run before the c ass s used Th s means that t s ca ed before any objects of that type are created or before any stat c members of the c ass are used It s as f the comp er
makes sure that the stat c constructor s ca ed the first t me t meets a ment on of the name CreditCardAccount
A stat c constructor s ke a norma constructor t has the same name as the c ass, and no return
type In add t on, stat c constructors have the static mod fier and do not take any arguments
ref class MyClass
{
public:
static MyClass() { ... }
...
};
You can eas y rewr te the CreditCardAccount c ass so that s uses a stat c constructor to n t a ze an
interestRate member
1. Cont nue us ng the project from the prev ous exerc se
2. Open Cred tCardAccount h and add a dec arat on for a pr vate member ca ed interestRate
static double interestRate;
3. Add the dec arat on for a stat c constructor n the pub c sect on of the c ass dec arat on
static CreditCardAccount();
4. Open Cred tCardAccount cpp and add the mp ementat on of the stat c constructor The ca
to WriteLine w
static CreditCardAccount::CreditCardAccount()
{
interestRate = 4.5;
Console::WriteLine("Static constructor called");
}
Be aware that you need the static keyword here You dont norma y use static outs de the
c ass dec arat on, but n th s case t s needed so that the comp er can determ ne that th s s
the stat c constructor
5. Bu d and run the app cat on Here s the code that you shou d have at the top of main
int n = CreditCardAccount::GetNumberOfAccounts();
Console::Write("Number of account initially:");
Console::WriteLine(n);
Console::WriteLine("\nCreating first object");
CreditCardAccount ^account1;
account1 = gcnew CreditCardAccount(12345, 2000);
You can see from th s that the stat c constructor s ca ed mmed ate y before the first object s
created
Those wh ch are constant and common to every object n the c ass For examp e, a Car c ass
m ght have a numberOfWheels member that s common to every Car nstance and wh ch has
a fixed va ue of 4
Those that are constant, but m ght be d fferent for each object For examp e, a BankAccount
object has an account number; th s s nd v dua to each nstance but cannot be changed after
t has been set
A literal can have an n t a va ue p aced n the c ass defin t on If you do th s, t must be a va ue that
the comp er can ca cu ate In other words, t cant depend on someth ng that w on y be known at
run t me
dec arat on
literal String ^name = "Super Platinum Card";
Because name s a constant, we can make t public because there s no danger that anyone can
mod fy t You can dec are tera s of bu t- n types, ref types, and va ue types
3. You can access the tera through the c ass name Add the fo ow ng code to d sp ay the name
Because the name be ongs to the c ass, you do not have to have any nstances n ex stence n
order to use t
4. Bu d and run the app cat on to see the va ue of the name pr nted out
It shou d run exact y the same as before because you are sett ng the va ue for accountNumber
n the constructor, as requ red by initonly
3. Open Cred tAccount cpp and try to ass gn a new va ue to accountNumber n one of the other
Too T p appears, nform ng you that the var ab e cannot be mod fied here
5. Remove th s ne of code before cont nu ng!
// Constructor
amountSpent);
// Earn one point per $10 spent
// Redeem points
// Return the value of totalPoints
// Total points earned so far
The syntax (int)(amountSpent/10) d v des the amount spent by 10 and converts the va ue to
anint
8. Imp ement the RedeemPoints member funct on as fo ows
void LoyaltyScheme::RedeemPoints(int points)
{
if (points <= totalPoints)
{
totalPoints -= points;
}
else
{
totalPoints = 0;
}
}
Th s funct on makes t poss b e for the user to redeem some or a of the accrued bonus po nts
9. Imp ement the GetPoints member funct on as fo ows
int LoyaltyScheme::GetPoints()
{
return totalPoints;
}
Note Relying on another object to do some work for you is an example of delegation. The CreditCardAccount object delegates the management of loyalty points to
the LoyaltyScheme object.
5. Open Cred tCardAccount cpp and find the CreditCardAccount constructor Add the fo ow ng
Note There is a big difference between not initializing the scheme handle at all and
initializing it to nullptr. Although the compiler is good at detecting attempts to use
uninitialized variables, it is good practice to explicitly initialize handles to null.
6. Mod fy the MakePurchase funct on to match the code that fo ows to co ect bonus po nts
{
// If LoyaltyScheme object doesn't exist yet...
if (scheme == nullptr)
{
// Create it
scheme = gcnew LoyaltyScheme();
}
else
{
// LoyaltyScheme already exists,
// so accrue bonus points
scheme->EarnPointsOnAmount(amount);
}
}
return true;
}
}
7. Imp ement the RedeemLoyaltyPoints funct on as shown n the code that fo ows Redeem
LoyaltyPoints s a new member funct on by wh ch the user can redeem some or a of the
oya ty po nts n the assoc ated LoyaltyScheme object
void CreditCardAccount::RedeemLoyaltyPoints()
{
// If the LoyaltyScheme object doesn't exist yet...
if (scheme == nullptr)
{
// Display an error message
Console::WriteLine("Sorry, you do not have a "
"loyalty scheme yet");
}
else
{
// Tell the user how many points are currently available
Console::Write("Points available: ");
Console::Write( scheme->GetPoints() );
Console::Write(". How many points do you want "
" to redeem? ");
// Ask the user how many points they want to redeem
String ^input = Console::ReadLine();
int points = Convert::ToInt32(input);
// Redeem the points
scheme->RedeemPoints(points);
// Tell the user how many points are left
Console::Write("Points remaining: ");
Console::WriteLine( scheme->GetPoints() );
}
}
Note Its important to check the value of the scheme handle before you use it. If you
forget to check the value and the handle is still null, your application will crash at run
time. This is a very common error in C++ applications.
8. Bu d the app cat on and fix any comp er errors
The app cat on creates a CreditCardAccount object and makes var ous purchases When the
cred t card ba ance reaches $1,000, a LoyaltyScheme object s created Subsequent purchases
co ect a oya ty po nt for every $10 spent
When you try to redeem oya ty po nts, the app cat on nforms you of how many po nts are ava ab e and asks how many you want to redeem Type a va ue such as 36 and press Enter The app cat on d sp ays how many po nts are eft
The fo ow ng screen shot shows the messages d sp ayed on the conso e dur ng the app cat on
Quick reference
To
Do this
Define a c ass.
mp ement a c ass.
CHAPTER 7
be ab e to
Descr be how M crosoft NET memory management d ffers from trad t ona C++ memory
management
ow that you know how to create objects n C++/CLI by us ng the gcnew operator, ts t me to
earn how to contro object fet mes as we as another way to create and use objects
You m ght want to do some c ean-up before the object s destroyed, such as wr t ng data back
to a database
The objects memory needs to be rec a med by the runt me
Lets see how th s s done n C++/CLI In NET, ke Java and many other modern anguages, the
runt me s respons b e for ensur ng that memory from dead objects s rec a med The component
that does th s s ca ed the garbage collector The runt me keeps track of hand es to objects, and when
an object can no onger be referenced through any hand e, t s unreachab e and s a cand date for
garbage co ect on
Th s means that programmers need to keep severa th ngs n m nd
Objects are a ways used through hand es, because thats the way that the system keeps track
of them
An object w
103
Move the ve objects, compact ng them to create the max mum amount of free space
Th s shou d exp a n why you refer to objects by us ng hand es not on y does t et the runt me track what s us ng an object, t a so so ates the user from where exact y n memory the
object s r ght at the moment
In rea ty, ts not qu te that s mp e Garbage co ect on s expens ve and affects the operat on
of your app cat ons, so ts best to not run a co ect on on the who e of memory f you dont
have to When des gn ng NET, M crosoft d scovered an nterest ng fact the onger an object
ves, the onger t s ke y to ve In other words, app cat ons tend to have a ot of objects that
come and go rap d y, and others that ve for a ong t me
Th s ed them to the dea of generations Every dynam ca y created NET object be ongs to
a generat on, and each generat on has ts own area of the managed heap Objects be ong to
generat on 0 when they are created; f generat on 0 fi s up, no more new objects can be created At th s po nt, the garbage co ector runs on the generat on 0 objects on y Any objects
that surv ve th s co ect on are promoted to generat on 1, and generat on 0 s c eared ready for
more new objects M crosofts observat on was that many objects ve and d e n generat on 0,
so onger- ved objects can be eft a one
At present, the NET garbage co ector has three generat ons (0, 1, and 2) You usua y et the
garbage co ector dec de when to perform a co ect on and wh ch generat on to co ect, but
you can use the System::GC::Collect stat c method to force a co ect on f you know you have a
ot of rec a mab e objects n your code W th Collect, you can run a defau t co ect on or spec fy
a part cu ar generat on If youre nterested n find ng out to wh ch generat on a part cu ar object
be ongs to, you can use the System::GC::GetGeneration method, pass ng n an object reference
Destructors
A destructor s executed when you no onger need an object To prov de a destructor for a c ass, add
a member funct on that has the same name as the c ass but s preceded by a t de character (~)
ref class MyClass
{
public:
MyClass();
~MyClass();
};
// constructor
// destructor
You can s gna that you no onger need an object by ca ng delete on a hand e to the object
// Create an Account
Account ^acc = gcnew Account();
// Use the Account
// We no longer need the Account
delete acc;
At th s po nt n the code the destructor s ca ed; thus, you know exact y where and when the
object has ceased to operate
L ke the constructor, they have no return type, and t s an error to g ve them one
They do not take any arguments, wh ch means they cannot be over oaded
Destructors are usua y pub c members of a c ass If you make them pr vate, you m ght not be
ab e to destroy objects of that type
Finalizers
F na zers are ca ed when the garbage co ector fina y rec a ms the objects memory You w need a
fina zer f you have unmanaged resources, such as po nters to unmanaged c asses, fi e hand es, w ndow hand es, graph c dev ce contexts, and so on If you dont have any of thoseand you on y tend
to do that when you are work ng w th unmanaged codeyou probab y dont need a fina zer
A fina zer s a member funct on that has the same name as the c ass but s preceded by an exc amat on mark (!)
ref class MyClass
{
public:
MyClass();
!MyClass();
};
// constructor
// finalizer
You can see that fina zers obey the same ru es as destructors; they have the same name as the
c ass and dont have a return type or take arguments
Th s m ght g ve you the mpress on that fina zers shou d be avo ded A though they are usefu n
some s tuat ons, you w find that you can norma y do whatever c eanup you requ re n the destructor
see how to create and use the fina zer and destructor for a c ass
1. Start V sua Stud o 2012 and create a new CLR Conso e App cat on ca ed Lifetimes
2. On the Project menu, c ck Add New Item
3. In the Add New Item d a og box, n the pane on the eft, se ect V sua C++, and then, n the
Note Another way that you can open the Add New Item dialog box is to right-click
the project name in Solution Explorer and then, in the shortcut menu that appears,
point to Add, and then click New Item.
5. Open the header fi e and add the dec arat on for a c ass that has a constructor, a destructor, a
//
//
//
//
constructor
destructor
finalizer
'work' method
Open the fi e and add #include statements for stdafx.h and MyClass.h
#include "stdafx.h"
using namespace std;
#include "MyClass.h"
7. Imp ement the constructor so that t stores the name n the data member and pr nts a mes-
Note Up to this point, you have used multiple Write and WriteLine statements to
build up a line of output. This exercise introduces a more efficient way: call WriteLine
or Write with a string that contains text and markers that consist of a number in
braces, such as {0} and {1}. The string should be followed by a list of items that you
want to print out. The first item will be output in place of {0}, the second in place of
{1}, and so on. We will use this from now on to save typing (and paper!).
8. Imp ement the destructor to pr nt a message to show that has been ca ed
MyClass::~MyClass()
{
Console::WriteLine("Destructor called for {0}", name);
}
9. Imp ement the fina zer to pr nt a message to show that t has been ca ed
MyClass::!MyClass()
{
Console::WriteLine("Finalizer called for {0}", name);
}
10. Imp ement the DoSomething method to pr nt out a message Th s s to show that the object
gcnew, and then ca DoSomething Remember to add a #include for MyClass.h, as shown here
#include "MyClass.h"
int main(array<System::String^>^ args)
{
MyClass ^m1 = gcnew MyClass("m1");
m1->DoSomething();
Console::WriteLine();
Console::WriteLine("End of program");
Console::WriteLine();
return 0;
}
When you create an object, ts constructor s ca ed If the app cat on fin shes and the object hasnt
been destroyed, the garbage co ector w ca the fina zer to c ear up any unmanaged resources
assoc ated w th the object
Not ce that two th ngs have happened first, the destructor has been ca ed at the po nt where you
ca ed de ete; second, the fina zer was not ca ed at the end of the app cat on
The destructor be ng ca ed when you ca delete means that you have comp ete contro over when
objects t dy themse ves up Th s deterministic destruction s a ha mark of trad t ona C++, and t s the
bas s of many common C++ cod ng d oms You shou d make a hab t of ca ng delete on your object
hand es when you no onger need them
We a so saw that as a resu t of ca ng delete, the fina zer wasnt executed The garbage co ector
dec des that you have dea t w th the d sposa of an object f ts destructor has been executed, and
so t doesnt need to execute ts fina zer Th s means that f you do have a fina zer, you shou d ca t
from the destructor to ensure that a unmanaged resources are freed up no matter how your objects
ex t
MyClass::~MyClass()
{
// Free up managed resources: this will be done anyway by the runtime
// Now call the finalizer to free unmanaged resources
this->!MyClass()
}
You can see two d fferences from C++/CLI code here The more obv ous of them s that you dont
use gcnew and you dont create a hand e Th s syntax creates an object ca ed m, and the constructor
parameters are passed after the object name n the same way as they were passed to gcnew when
creat ng an object dynam ca y The second obv ous d fference s that members of the object are
accessed by us ng the dot operator ( ) rather than ->
There s one mportant consequence to creat ng objects n th s way, apart from t tak ng s ght y
ess typ ng When you create an object n th s manner, ts destructor s ca ed automat ca y at the end
of the b ock of code Th s s shown n the fo ow ng code samp e
{
MyClass m("m3");
m.DoSomething();
// Destructor for m is called here
Such objects are somet mes ca ed automatic objects because they are automat ca y destroyed
when they go out of scope
Note In C++, scope refers to where in the code an object is visible. It is often related to an
objects lifetime. In this case, m cannot be seen outside the block, so it goes out of scope at
the final brace.
Th s s a huge benefit to programmers you can create an object and then know exact y where and
when t w be destroyed and t dy tse f up w thout the need for you to ca delete In standard C++
these objects are created n an area of memory ca ed the stack, and so we say that these objects
exh b t stack semantics
Note In C++/CLI, these objects are not actually declared on the stack. This notation is a
convenience that makes it possible for you to work with objects in the traditional C++ way,
but under the hood, our objects are still created and managed by using handles.
1. Cont nue us ng the project from the prev ous exerc se
2. Ed t the main funct on by add ng code to create and use another object, p ac ng t before the
end of program WriteLine ca s Ensure that you create th s object by us ng stack semant cs
MyClass m2("m2");
m2.DoSomething();
After the output for m1, you shou d see output s m ar to the fo ow ng
Constructor called for m2
DoSomething called for m2
End of Program
Destructor called for m2
You create and use the object, but do not manua y de ete t The destructor s ca ed automat ca y
when execut on passes the end cur y bracket n the funct on
Note You can create most types of objects by using stack semantics, but you cannot do
this for Strings or arrays. For those types you must use gcnew to get a handle, and you
access the objects by using the -> operator.
That s fine, but what f you forget to sw tch the cursor back? Or more ke y, what happens
f an error occurs and the SetCursorToArrow ne s never executed? You are eft w th the cursor
stuck as an hourg ass, and the user becomes annoyed
One so ut on s to create a sma he per c ass Th s carr es out one task t sets the cursor to
an hourg ass n ts constructor and then sets t back to the arrow n ts destructor
ref class BusyCursorHelper
{
public:
BusyCursorHelper { SetCursorToHourglass(); }
~BusyCursorHelper { SetCursorToArrow(); }
};
The object s created and sets the cursor At the fina brace, t s destroyed, and that sets the
cursor back to an arrow Important y (and as s demonstrated n Chapter 11, Except on hand ng) th s even happens f there s an error
Th s examp e of the RIAA d omdo ng someth ng n the constructor and undo ng t n the
destructorshows how somet mes you m ght create a c ass s mp y for the s de-effects you get
when us ng t
Copy constructors
A copy constructor s a spec a k nd of constructor funct on that takes an object of the same type as
ts argument In other words, you can create an object as a copy of another one In th s sect on you
see how to wr te and use a copy constructor, but you a so earn about two other mportant concepts dereferenc ng and track ng references
If you run th s code, t pr nts out Value: 3, str: abc The hand e one po nts to a new MyClass
object created through gcnew The hand e two s s mp y a copy of one; n other words, t po nts to the
same object as one Copy ng a hand e doesnt copy the object to wh ch t po nts And, f you mod fy
the va ue member of two, the va ue for one w be changed, as we , because they are referr ng to the
same object
Suppose, though, that we d d want to make two a copy of one In that case, we wou d prov de a
copy constructor for the c ass, wh ch wou d ook ke th s
MyClass(const MyClass %other)
{
value = other.value;
str = other.str;
}
The constructor takes another MyClass object and cop es ts members The value s an int, so a
copy of the va ue s made The str member s a hand e to a str ng, but because str ngs are mmutab e,
t doesnt matter that were po nt ng to the same one
But, ook more c ose y at the dec arat on of the argument What s a const MyClass%? The percent
(%) symbo ntroduces what s ca ed a tracking reference A hand e ets you refer to an object nd rect y, and you use the -> operator to access members A track ng reference s rea y an a as, another
name for a var ab e Cons der th s code fragment
int i = 5;
int %ri = i;
// ri is a tracking reference
Pr nt ng out ri pr nts 5, because ri and i refer to the same var ab e In many ways references are
safer than hand es because t s poss b e to have a hand e that hasnt been ass gned, but t s d fficu t
to create an un n t a zed reference
You can have references to bu t- n types, to managed objects, and to hand es When you have a
track ng reference to a managed object, the runt me ensures that t a ways refers to the r ght ocat on
n memory, even f the garbage co ector moves th ngs around
Note In the same way that a handle is the C++/CLI version of a standard C++ pointer, a
tracking reference is the C++/CLI version of a standard C++ reference. It differs from a standard reference because the garbage collector can relocate the object being referred to during memory compaction.
So, we now know that the copy constructor takes a track ng reference to an object rather than a
hand e The reference s marked as const because t ets us make cop es of constant MyClass objects,
wh ch the comp er otherw se wou d not a ow
The other construct that we need to cover s dereferencing Heres another code fragment
MyClass ^m = gcnew MyClass();
MyClass %rm = *m;
The first ne creates a MyClass object by us ng gcnew and returns a hand e to t The second ne
returns a reference to m by us ng the dereference operator, * (the aster sk character) You can read
*m as what m po nts to
However, th s st hasnt created a copy m and rm are st
But, what about th s code?
MyClass mm = *m;
Here, mm s a MyClass w th stack semant cs, and the code s say ng create me a new object, mm,
as a copy of the one to wh ch m s po nt ng It s at th s po nt that the copy constructor s nvoked
Th s exerc se shows you how to mp ement a copy constructor for a c ass
1. Create a new CLR Conso e App cat on named CopyCon
2. Add the fo ow ng c ass defin t on before the main funct on
ref class MyClass
{
int value;
String ^str;
public:
MyClass(int v, String ^s) : value(v), str(s) {}
MyClass(const MyClass %other)
{
Console::WriteLine("copy con called");
value = other.value;
str = other.str;
}
int getValue() { return value; }
void setValue(int v) { value = v; }
String ^getString() { return str; }
};
MyClass has two data members an int and a String hand e The norma constructor n t a zes
these two from the va ues passed n, and you can use the s mp e getter funct ons to retr eve
the va ues ater on
The hand e one s created to po nt to a MyClass object, and the hand e two s a copy of
one You can ver fy th s by pr nt ng out the data by us ng the two hand e The object three
s created by dereferenc ng one, wh ch creates a copy You can ver fy that th s s the case by
chang ng the data n three and show ng that t hasnt changed the data n one
4. Bu d and run the app cat on Check that you understand the output
4. Add a source fi e ca ed Geometry cpp to the project and mp ement the Point and Rectangle
c ass members
#include "stdafx.h"
using namespace System;
#include "Geometry.h"
Point::Point()
{
Console::WriteLine("Point constructor called");
}
Point::~Point()
{
Console::WriteLine("Point destructor called");
}
Rectangle::Rectangle()
{
Console::WriteLine("Rectangle constructor called");
}
Rectangle::~Rectangle()
{
Console::WriteLine("Rectangle destructor called");
}
You can see from th s output that the Point members of the Rectangle are constructed before
the Rectangles constructor s ca ed If you th nk about t, th s s qu te og ca when n t a z ng tse f,
the Rectangle m ght want to use the Points to set some other propert es, such as ts area or d agona
ength So, t makes sense for the composed objects to be constructed before the constructor for the
outer object s executed
The destructors are ca ed n reverse order, w th the Rectangle destructor be ng ca ed before
thedestructors for the Points The Point objects are not destroyed unt you can be sure that the
Rectangle no onger needs them
Note If you want to create an object that takes no arguments in the constructor, do not put
empty parentheses after the variable name.
Rectangle r();
If you do this, you will get a warning (C4930) and the application will not give the correct
output when you run it. The reason is that the compiler takes this as a function prototype
declaration rather than a variable declaration. It is not helpful behavior, but has been a part
of traditional C++ since the earliest implementations.
What s the d fference between these two, and why m ght you choose one over the other?
The one you choose depends on the nature of the re at onsh p between the two objects It s beyond the scope of th s book to g ve a fu exp anat on of object-or ented des gn, but here are a coup e
of examp es to ntroduce you to the deas
The quest ons you need to ask are the fo ow ng
Is the conta ned object a part of ts conta ner, such that t has no ndependent ex stence?
Cou d you swap the conta ned object for another one?
Cons der the case of an object that represents a bus ness meet ng Th s has propert es such as
descr pt on, date and t me, but t a so has a ocat on, wh ch s represented by a Location object The
Location object ho ds a the deta s about a meet ng room where t s, the phone number, how many
peop e t can ho d, whether t has conference fac t es, and so on
Obv ous y many meet ngs can use the same Location at d fferent t mes, so they w have a reference to the same Location object It s a so poss b e that the meet ng can be moved, so you need to
be ab e to change the Location And obv ous y, the Location doesnt cease to ex st when a meet ng s
over Th s makes t a sens b e dea to use a hand e to a Location object n the Meeting c ass
As a second examp e, cons der the Rectangle/Point exerc se aga n The Points are parts of the
Rectangle; they w d sappear when the Rectangle object reaches the end of ts fe There s no way
that we are go ng to share a Point w th anyone e se, and so t makes sense that Points are conta ned
w th n the Rectangle
Quick reference
To
Do this
CHAPTER 8
Inheritance
After comp et ng th s chapter, you w
be ab e to
Use nterfaces
n th s chapter, you w earn how to use a aspects of nher tance n C++/CLI You w see how to
define base c asses and der ved c asses, and you w find out how to use these c asses effect ve y n
your app cat on
What is inheritance?
Inher tance s an mportant concept n object-or ented programm ng, he p ng us re ate and c ass fy
types n a way that makes our app cat ons more type-safe, flex b e, and extens b e
Note Type-safe means that the type system makes it easy to use the correct type in the
correct place, and its easy for the compiler to spot any mistakes that you make.
As an examp e, cons der cars, trucks, and buses A of these are types of veh c es we can say that a
car s a veh c e and that a sports car s a car We tend to c ass fy the wor d n terms of more genera
and more spec fic types a the t me A manager s a so an emp oyee; a sav ngs account s an account;
and so on
121
How we v ew th ngs depends on the job we need to do If I just need to dr ve down the b ock, I
cou d use any k nd of car; for examp e, a sports car wou d do, as wou d an SUVas ong as t s a car
But, f I need to take my fam y to the a rport, a sports car wont do I need to be more spec fic
Inher tance ets you use th s c ass ficat on mechan sm n your code If I am wr t ng an app cat on
to mon tor traffic flow, I m ght have a funct on to count the number of veh c es pass ng a g ven po nt
Us ng nher tance, the comp er knows that cars, trucks, and buses are a veh c es, so I can pass a of
those to the funct on
The advantages of nher tance are we documented, resu t ng n better-structured code that s
eas er to work w th and ma nta n
Inheritance terminology
When you use nher tance you are dea ng w th an s a re at onsh p between a parent c ass and one
or more ch d c asses You w find that there are severa terms used to descr be th s re at onsh p,
nc ud ng the fo ow ng
Us ng the correct terms for your anguage s, of course, not as mportant as gett ng the re at onsh ps correct
Note This illustration uses Unified Modeling Language (UML) notation to represent inheritance. Each box in this diagram is a class. The arrow pointing to BankAccount denotes
inheritance in UML.
BankAccount s the base c ass It defines common data members and member funct ons that are
common to a k nds of bank accounts
CurrentAccount and SavingsAccount are der ved c asses, represent ng spec fic types of bank account These der ved c asses nher t a the data members and member funct ons from BankAccount,
and they can add extra data members and member funct ons, as requ red
CurrentAccount and SavingsAccount can a so overr de member funct ons defined n BankAccount
For examp e, the BankAccount c ass m ght have a method named CanDebit to nd cate whether a
certa n amount of money can be deb ted from the account The po cy ru es for a ow ng deb ts are
d fferent for each type of account; therefore, CurrentAccount and SavingsAccount can overr de the
CanDebit method to perform the requ red process ng for each type of account
You w define and mp ement a three of these c asses dur ng th s chapter Lets beg n w th the
base c ass, BankAccount
A word on substitutability
Substitutability means that everywhere you want a base c ass object, you can use a der ved c ass
object For examp e, f I ask you to br ng me a veh c e (base c ass), a car or a truck (der ved c ass) w
suffice because I wasnt spec fic I expect, however, that anyth ng you br ng me s a veh c e, and as a
m n mum does everyth ng that a veh c e can do
For th s reason, der ved c asses can add funct ona ty over and above the r base c ass, and can
redefine operat ons that they nher t, but they are not a owed to remove funct ona ty
You can regard the funct ona ty prov ded by the base c ass as a contract that the der ved c ass
must honor If t doesnt, t s not subst tutab e for the base c ass, and the nher tance re at onsh p s
not proper
Tip Always start by deciding what it is that a class must do, and then think about what data
members are needed to support these operations.
In th s exerc se, you w create a new app cat on and define the BankAccount c ass The BankAccount
c ass w be the base c ass for a types of bank accounts n the app cat on
In BankAccount, you w define the common member funct ons and data members that app y for
a types of bank accounts You w a so define a constructor and destructor for th s c ass
1. Start V sua Stud o 2012 and create a new CLR Conso e App cat on project named BigBank
2. On the Project menu, c ck Add New Item
3. In the Add New Item d a og box, n the pane on the eft, se ect V sua C++, and then, n the
Add
Note Another way that you can open the Add New Item dialog box is to right-click
the project name in Solution Explorer and then, in the shortcut menu that appears,
point to Add, and then click New Item.
5. Define the BankAccount c ass as fo ows
#pragma once
using namespace System;
TipThe #pragma once compiler directive specifies that this header file will be processed only once by the compiler during a build. This directive is particularly useful
for frequently included header files, such as those containing base-class definitions.
If you omit the #pragma once directive, you will almost certainly get a compiler error when you try to build the application later on because BankAccount.h will be
included in several different places in the application, and the compiler will generate
an error if it sees the BankAccount class declaration more than once.
6. Repeat steps 2 through 4, but th s t me add a new C++ source fi e named BankAccount.cpp
to the project
7. Type the fo ow ng code n the source fi e to mp ement the BankAccount c ass
#include "stdafx.h"
#include "BankAccount.h"
BankAccount::BankAccount(String ^holder)
: accountHolder(holder), balance(0.0)
{
}
void BankAccount::Credit(double amount)
{
balance += amount;
}
void BankAccount::Debit(double amount)
{
balance -= amount;
}
double BankAccount::GetBalance()
{
return balance;
}
Note The constructor uses a member initialization list to initialize the BankAccount
data members, which is the preferred syntax for initializing data members in a constructor. Furthermore, its the only way to invoke base-class constructors, which will
become apparent when you define the CurrentAccount and SavingsAccount classes
shortly.
The co on n the c ass defin t on nd cates nher tance Fo ow ng the co on, you spec fy the name of
the base c ass
Note In standard C++ you would put one of the keywords public, protected, or private after
the colon and before the base class name. C++/CLI (and all other Microsoft .NET languages)
only support public inheritance, so you do not need to use the public keyword. It is not an
error if you use it, but be aware that it is not required.
In th s exerc se, you w define and mp ement the CurrentAccount and SavingsAccount c asses
CurrentAccount w nher t from BankAccount, wh ch means that there s no need to re mp ement
nher ted member funct ons such as Credit and Debit L kew se, there s no need to redefine nherted data members such as accountHolder and balance A you need to define n CurrentAccount are
add t ona member funct ons and data members, wh ch app y spec fica y to current accounts
SavingsAccount w have an nterest rate assoc ated w th t Because the nterest rate s common to
a SavingsAccount objects, t makes sense to make t a stat c member of the c ass
1. Cont nue us ng the project from the prev ous exerc se
2. Add a new header fi e to the project named CurrentAccount.h
3. Type the fo ow ng code n the header fi e to define the CurrentAccount c ass
#pragma once
#include "BankAccount.h"
ref class CurrentAccount : BankAccount
{
public:
CurrentAccount(String ^holder, double limit);
void ChangeOverdraftLimit(double newLimit);
double GetOverdraftLimit();
private:
double overdraftLimit;
};
Not ce the #include BankAccount.h d rect ve Th s d rect ve s requ red because BankAccount
s the base c ass of CurrentAccount The comp er needs to know how BankAccount s defined
to comp e the CurrentAccount c ass
A so not ce that the CurrentAccount constructor takes two parameters; the first parameter
n t a zes the account ho ders name (defined n BankAccount), and the second n t a zes the
overdraftLimit (defined n CurrentAccount)
4. Add a new C++ source fi e to the project named CurrentAccount.cpp
5. Type the fo ow ng code n the source fi e to mp ement the CurrentAccount c ass
#include "stdafx.h"
#include "CurrentAccount.h"
CurrentAccount::CurrentAccount(String ^holder, double limit)
: BankAccount(holder), overdraftLimit(limit)
{
}
void CurrentAccount::ChangeOverdraftLimit(double newLimit)
{
overdraftLimit = newLimit;
}
double CurrentAccount::GetOverdraftLimit()
{
return overdraftLimit;
}
The most mportant th ng to note about th s code s the CurrentAccount constructor The
member n t a zat on st nc udes the syntax BankAccount(holder) Th s ca s the constructor nthe base c ass, BankAccount, to n t a ze nher ted data members If you take a ook n
BankAccount cpp, you see that the BankAccount constructor requ res a String^ parameter to
set the account ho ders name The ba ance s a ways set to 0 n t a y
Note The derived-class constructor must call the base-class constructor by using the member initialization list syntax. If you forget to call the base-class constructor, the compiler will
attempt to call a no-argument constructor in the base class on your behalf; if there isnt a
no-argument constructor in the base class, youll get a compiler error.
6. Add a header fi e to the project named SavingsAccount.h
7. Add the fo ow ng dec arat on for the SavingsAccount c ass to the fi e
#pragma once
#include "BankAccount.h"
ref class SavingsAccount : BankAccount
{
public:
SavingsAccount(String ^holder);
static void SetInterestRate(double rate);
static double GetInterestRate();
private:
static double interestRate;
};
exerc se t
CurrentAccount acc("Me", 2000.0);
acc.Credit(100.0);
double balance = acc.GetBalance();
double overdraft = acc.GetOverdraftLimit();
Console::WriteLine("Balance: {0}", balance);
Console::WriteLine("Overdraft: {0}", overdraft);
You can see that the CurrentAccount object g ves you access to the Credit and GetBalance member funct ons from Account. It a so g ves you access to ts own GetOverdraftLimit funct on
4. Add code to main to create a SavingsAccount
SavingsAccount::SetInterestRate(2.5);
SavingsAccount sacc("You");
double rate = sacc.GetInterestRate();
Console::WriteLine("Interest rate: {0}", rate);
You shou d see the nterest rate pr nted, show ng that you can access a stat c member through
e ther the c ass name or through an object
6. Bu d and run the app cat on
Observe how the abstract mod fier appears after the c ass name
In th s exerc se, you w mod fy the BankAccount c ass as just descr bed to make t an abstract c ass
You w then wr te some code n the main funct on n the app cat on to create and use CurrentAccount
and SavingsAccount objects
130Microsoft Visual C++/CLI Step by Step
keyword
ref class BankAccount abstract
{
...
};
3. Open B gBank cpp to ed t the main funct on for the app cat on
4. Ins de the main funct on, try to create a BankAccount object as fo ows
BankAccount genericAccount("Fred");
Inte Sense flags an error, wh ch confirms the fact that you cannot create nstances of an
abstract c ass
5. De ete the statement you created n Step 4
The base-c ass funct on s su tab e for a der ved c asses Der ved c asses w never need to
overr de the member funct on w th custom zed behav or The Credit and GetBalance member funct ons n BankAccount fit th s scenar o These funct ons w work the same way for a
der ved c asses Heres an examp e
ref class BankAccount abstract
{
public:
void Credit(double amount);
double GetBalance();
...
};
The base-c ass funct on performs some task, but der ved c asses m ght need to overr de the
funct on to prov de custom zed behav or To make t poss b e to overr de a base-c ass funct on, you must dec are the funct on by us ng the virtual keyword n the base-c ass defin t on,
as shown n th s examp e
ref class BankAccount abstract
{
public:
virtual String ^ToString() override;
...
};
Th s funct on dec arat on uses both the virtual and override keywords We have seen how
virtual nd cates that a der ved c ass can overr de th s funct on The override keyword must be
used when you are overr d ng a funct on from a base c ass; n th s case, ToString s defined n
the u t mate base c ass, System::Object, and so we use override to show that we are ntend ng
to overr de th s funct on and havent just added a funct on that ooks exact y the same
If by some chance you want to add a funct on that ooks ke a base c ass funct on but does
not overr de t, you wou d use the new mod fier
// This function does not override ToString
virtual String ^ToString() new;
The base-c ass funct on spec fies some operat on that s requ red by a der ved c asses, but
each der ved c ass needs to perform the operat on n a s gn ficant y d fferent way There s no
sens b e common behav or you can define n the base c ass To do th s, you dec are the basec ass member funct on as abstract C++ ca s these pure virtual functions
There are two ways to denote a pure v rtua funct on The first comes from standard C++ and
nvo ves putt ng = 0 at the end of the funct on dec arat on The second way, ntroduced by
C++/CLI, s to add the abstract keyword Heres an examp e
ref class BankAccount abstract
{
public:
// Declare a pure virtual function using standard C++ syntax
virtual void Debit(double amount) = 0;
// Declare a pure virtual function using C++/CLI syntax
virtual void Debit(double amount) abstract;
...
};
Note Including a pure virtual function in a class means that it must be abstract, although
the opposite is not necessarily true: a class can be abstract without having any pure virtual
functions. If a derived class does not implement the function, it too must be abstract.
In th s exerc se, you w define a ToString member funct on n the BankAccount c ass You w
dec are th s funct on as v rtua to g ve der ved c asses the opportun ty to overr de the funct on f
they want to You w a so mod fy the way n wh ch deb ts are hand ed so that der ved c asses dec de
whether a w thdrawa can be made
1. Cont nue us ng the project from the prev ous exerc se
2. Open BankAccount h and add the fo ow ng pub c funct on dec arat ons to the BankAccount
c ass
// Derived classes can override this function
virtual String ^ToString() override;
// Derived classes must override this function
// You can use '=0' instead of 'abstract'
virtual bool CanDebit(double amount) abstract;
Observe the use of the String::Concat funct on, wh ch s used for jo n ng str ngs together
4. Mod fy the Debit member funct on as fo ows
bool BankAccount::Debit(double amount)
{
if (CanDebit(amount))
{
balance -= amount;
return true;
}
else
{
return false;
}
}
Not ce that Debit now ca s CanDebit to ver fy that the deb t s a owed CanDebit snt mp emented n BankAccount, but a der ved c asses are ob ged to prov de th s funct on At run
t me, the correct vers on of CanDebit s ca ed depend ng on the type of bank account be ng
used for the deb t operat onpo ymorph sm n act on! We have a so changed the return type
of Debit so that ca ng code can determ ne whether the deb t worked
5. Change the prototype for Debit n BankAccount h so that t returns a bool
6. Open CurrentAccount h and add the fo ow ng pub c funct on dec arat ons to the Current
Account c ass
// Choose to override ToString
virtual String ^ToString() override;
// Have to override CanDebit
virtual bool CanDebit(double amount) override;
Not ce the use of the override keyword Th s nstructs the comp er that you are ntend ng to
overr de a funct on from the base c ass and havent just added a funct on that happens to ook
exact y the same
7. Open CurrentAccount cpp and mp ement the ToString funct on as fo ows
String ^CurrentAccount::ToString()
{
String ^result = BankAccount::ToString();
result = String::Concat(result, ", Overdraft Limit: ");
result = String::Concat(result, overdraftLimit.ToString());
return result;
}
The BankAccount::ToString() syntax ca s the ToString funct on n the base c ass (BankAccount)
Th s ca returns a str ng conta n ng the account ho ders name and ba ance We concatenate
the overdraftLimit va ue to th s str ng and return t
8. St
There are two th ngs to note about th s code F rst, we need to ca the GetBalance funct on to
get the current ba ance Just because we nher t from BankAccount doesnt mean that we can
access ts pr vate balance member
Second, not ce the way n wh ch the return statement s wr tten, return ng the resu t of the
express on d rect y We cou d have used an if statement to check the cond t on and return true
or fa se, but th s code s shorter wh e be ng no ess readab e, and that s someth ng that C++
coders ke
9. Open Sav ngsAccount h and add the fo ow ng pub c funct on dec arat on to the Savings
Account c ass
virtual bool CanDebit(double amount) override;
You are ob ged to overr de CanDebit because ts a pure v rtua funct on However, you do not
have to overr de ToString, because the base c ass (BankAccount) prov des a defau t mp ementat on of th s funct on The SavingsAccount c ass chooses not to overr de ToString
10. Open Sav ngsAccount cpp and mp ement the CanDebit funct on as fo ows
bool SavingsAccount::CanDebit(double amount)
{
return (amount <= GetBalance() / 10);
}
Th s funct on makes t poss b e for the user to w thdraw one-tenth of the current ba ance
134Microsoft Visual C++/CLI Step by Step
11. Open B gBank cpp and rep ace the ex st ng code n the main funct on w th the fo ow ng
Console::WriteLine("Testing the CurrentAccount");
CurrentAccount current("Jane", 100);
current.Credit(500);
// Should be accepted
if (current.Debit(550) == true)
{
Console::WriteLine("Debit(550) OK");
}
else
{
Console::WriteLine("Debit(550) failed");
}
// Should be declined
if (current.Debit(100) == true)
{
Console::WriteLine("Debit(100) OK");
}
else
{
Console::WriteLine("Debit(100) failed");
}
Console::WriteLine(current.ToString());
Console::WriteLine("\nTesting the SavingsAccount");
SavingsAccount savings("Fred");
savings.Credit(500);
// Should be accepted
if (savings.Debit(50) == true)
{
Console::WriteLine("Debit(50) OK");
}
else
{
Console::WriteLine("Debit(50) failed");
}
// Should be declined
if (savings.Debit(46) == true)
{
Console::WriteLine("Debit(46) OK");
}
else
{
Console::WriteLine("Debit(46) failed");
}
Console::WriteLine(savings.ToString());
return 0;
12. Bu d and run the app cat on Check that the output s what you expect
13. Create a breakpo nt on the first statement n the main funct on and then start the app cat on
n the debugger Step through the app cat on one statement at a t me, stepp ng nto each
funct on to see wh ch vers on s ca ed dur ng execut on
Protected access
You have used two access eve s for c ass members so far private and public You know that private
members cannot be used outs de the defin ng c ass, whereas public members can be used by anyone
Inher tance, however, ntroduces a re at onsh p between two c asses, and there s a need for an access
eve that grants access to der ved c asses The protected access eve s ess restr ct ve than private but
more restr ct ve than public
Any members that are defined as protected can be used n the base c ass, and n any c ass that der ves
from t
Tip You should only make member functions protected, not data members. The data belonging to a class is the responsibility of that class, and it should not allow direct modification by derived classes.
In th s examp e, you w add a protected member funct on to the BankAccount c ass Suppose that
BankAccount has a RoutingInstructions funct on that deta s how a g ven s ze of deb t or cred t shou d
be hand ed for a part cu ar account Th s funct on s not to be accessed by users of the c ass but m ght
be of use to der ved c asses
1. Cont nue us ng the project from the prev ous exerc se
2. Open BankAccount h and add the fo ow ng protected funct on dec arat on to the BankAccount
c ass
protected:
String ^RoutingInstructions(double amount);
Note The order in which you specify the public, private, and protected sections of a
class declaration does not matter, although many people will put the public section
first because that is the most important section from the point of view of users of
the class.
3. Open BankAccount cpp and add the defin t on of RoutingInstructions
String ^BankAccount::RoutingInstructions(double amount)
{
return "Some string";
}
4. Open CurrentAccount cpp and mod fy the CanDebit funct on so that t ca s RoutingInstructions
You shou d not see any warn ngs from the comp er, because CurrentAccount s a owed to ca
th s funct on
bool CurrentAccount::CanDebit(double amount)
{
String ^details = RoutingInstructions(amount);
return (amount <= GetBalance() + overdraftLimit);
}
5. Open B gBank cpp and try add ng a ca to RoutingInstructions on e ther the SavingsAccount or
CurrentAccount objects
Inte Sense flags an error because you are not a owed to ca th s funct on from an unre ated
c ass If you bu d the project, you w get error C3767 (BankAccount Rout ngInstruct ons
cand date funct on(s) not access b e)
Note You can specify the sealed and abstract modifiers in any order.
Th s c ass spec fies how to convert data to and from XML, and t s mp emented by der ved c asses
to su t the r part cu ar data You cou d use the fo ow ng
ref class MyData : XmlWriter
{
public:
void ReadFromXmlFile(String ^filename) override
{
// Read my data
}
void WriteToXmlFile(String ^filename) override
{
// Write my data
}
};
An nterface s s m ar, and you cou d rewr te the XmlWriter c ass as fo ows
interface class IXmlWriter
{
void ReadFromXmlFile(String ^filename);
void WriteToXmlFile(String ^filename);
};
The defin t on of the der ved c ass a so needs to be changed You need to spec fy the nterface
name, and dec are the funct ons as virtual
ref class MyData : IXmlWriter
{
public:
virtual void ReadFromXmlFile(String ^filename)
{
// Read my data
}
virtual void WriteToXmlFile(String ^filename)
{
// Write my data
}
};
You can see that you nher t from an nterface n the same way that you nher t from a c ass However, there are a number of d fferences between a c ass and an nterface
A c ass can on y nher t from one base c ass, but t can mp ement as many nterfaces as t
wants
If you have used standard C++, you m ght know that a c ass can nher t from many base c asses
Th s feature s ca ed multiple inheritance NET on y a ows you to nher t from one base c ass, but
because you can mp ement as many nterfaces as necessary, you can get the benefits of mu t p e
nher tance
Interfaces are very mportant n NET, not east of wh ch because they are cross- anguage You can
define an nterface n C++ and mp ement t n C# More mportant than that, they prov de a way to
spec fy a contract, wh ch one c ass mp ements, and another uses Ne ther c ass m ght have know edge of the other, but they can commun cate because they both know about and use the nterface
contract You w see many examp es of nterfaces as you progress through the rest of the book
Quick reference
To
Do this
PAR T I I
Microsoft .NET
programming basics
CHAPTER 9
Va ue types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
143
CHAPTER 10
159
CHAPTER 11
Except on hand ng . . . . . . . . . . . . . . . . . . . . . . . . . .
175
CHAPTER 12
197
CHAPTER 13
Propert es . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
229
CHAPTER 14
245
CHAPTER 15
263
141
CHAPTER 9
Value types
After comp et ng th s chapter, you w
be ab e to
Work w th structures
n preced ng chapters, you earned about object-or ented programm ng and how to app y t w th n
the M crosoft NET Framework Youve seen how many data types w th n NET are represented by
c asses, and youve earned how to create and use your own c asses However, not every data type n
NET s a c ass, and now youre go ng to meet the other fundamenta bu d ng b ock of NET types
the va ue type
In th s chapter, you d scover what va ue types are and how they d ffer from the reference types
youve a ready met You w a so earn about two mportant va ue types, structures and enumerat ons,
wh ch w be usefu n your own code
143
Structures
Structures (common y referred to as structs) prov de a way to create the compound data or record
types that you m ght have come across n other programm ng anguages S m ar to c asses, structures
can conta n member funct ons, data members, and other NET features that you earn about n
ater chapters, but theres one mportant d fference structures are va ue types, not reference types
Therefore, f you have a va ue type that needs to have some nterna structure, such as a po nt w th
Xand Y coord nates, you can mp ement t by us ng a struct
Note Both standard C++ and C++/CLI use the struct keyword to define structures. This
chapter discusses the use of .NET (managed) structs rather than the traditional struct.
Declaring .NET structures has the advantage of working within the .NET world and also
makes it possible for you to exchange structures with other .NET languages.
1. Start M crosoft V sua Stud o 2012 and create a new CLR Conso e App cat on project named
Structs
2. At the top of the Structs cpp fi e, mmed ate y be ow the using namespace System; ne, add the
fo ow ng structure defin t on
// The Point structure definition
value struct Point
{
int x, y;
};
The value and struct keywords start a structure defin t on, and you not ce that structures
ook very s m ar to c asses n the way that they are defined The body of the structure s
enc osed n braces and fin shes w th a sem co on, and the public and private keywords can be
used to set the access eve for structure members
Not ce the use of the value keyword here Th s keyword nstructs the comp er that th s s a
NET va ue type and not a trad t ona C++ structure Its mportant that you remember to use
value when defin ng your structures
Th s s mp e structure represents a po nt on a graph, so t has two nteger data members represent ng the X and Y coord nates
Note In standard C++ the only difference between a struct and a class is in the default access level. Members of a class are private by default, whereas members of a
struct are public, unless marked otherwise. This has been carried over into C++/CLI,
so there is no need to make structure members public.
3. To create and n t a ze a Point object, add the fo ow ng nes to the main funct on of your
app cat on
// Create a Point
Point p1;
// Initialize its members
p1.x = 10;
p1.y = 20;
Not ce that the code doesnt use the gcnew operator The gcnew operator s used to create
references to objects, and va ue types arent accessed by reference Instead, a Point has been
created on the program stack, and you access t d rect y as p1 Because the data members are
pub c at th s po nt, you can access them by us ng the fam ar dot notat on
4. Add two nes to pr nt out the va ue of one of the structure members, ke th s
Console::WriteLine("p1.x is {0}", p1.x);
After the app cat on oads, t executes and stops at the breakpo nt You can now use the
Loca s pane at the bottom of the w ndow to ook at the structure of the Point type
You shou d see an entry for the var ab e p1 Any type that has nterna structuresuch as
Point s nd cated by a p us s gn (+) to the eft of the var ab e name
4. C ck the p us s gn to expand the structure
The Loca s pane opens, appear ng s m ar to the one shown n the fo ow ng screen shot
You can see that p1 has three entr es be ow t The first shows that ts der ved from
System::ValueType, wh ch s n turn der ved from System::Object The other two are the x and
y members, wh ch are both 32-b t ntegers At th s po nt n n the code, the structure hasnt
been fu y n t a zed, so they dont conta n sens b e va ues
5. Press F10 three t mes to n t a ze p1 and execute the next two ass gnment statements
Th s act on resu ts n p1 be ng n t a zed, and you w see the va ues of x and y change to reflect the va ues you set The va ues a so change from b ack to red n the Loca s pane, show ng
that they were changed n the prev ous execut on step
6. Cont nue press ng F10 to s ng e-step through the code, exam n ng the changes that occur to
p1 as you execute each ne When youre done, d scont nue debugg ng by c ck ng the Stop
Debugg ng button on the too bar (the dark-red square), c ck ng the Stop Debugg ng command on the Debug menu, or press ng Sh ft+F5
You cant n t a ze members n a structure defin t on If you need to prov de n t a zat on for a
structure type, you must prov de a constructor
You cant overr de the defau t no-argument constructor for a structure Th s s because the
runt me automat ca y sets a members of a structure to the r defau t va ues 0 for numer c
types, and fa se for Boo eans
Structures cant have destructors or fina zers, because they arent garbage co ected
Inher tance snt app cab e to structures, so they cant nher t from anyth ng e se and you cant
use them as a base c ass
Structures can mp ement nterfaces
The constructor takes two int va ues and uses them to n t a ze the x and y data members
In th s case, the arguments are s mp y be ng cop ed nto the data members, but t wou d be
s mp e to add some check ng to ensure that the data passed n s correct
Note Anyone who has used C++ before will be familiar with the use of default arguments on constructors. You cant use default arguments on managed types in C++/
CLI, so you need to provide an explicit default constructor.
3. You can now add extra code to your main funct on to create n t a zed Points
Point p2(10,20);
4. Bu d and run the app cat on Check that the resu t s what you expect
You can see how the Date structure conta ns three members represent ng the day, month, and
year Th s structure s qu te genera , so you cou d use t n other app cat ons The Person structure
conta ns a String reference to ho d the name, and a Date object to ho d the date of b rth
In th s exerc se, you use these two c asses to nvest gate how structure data members work
1. Create a new CLR Conso e App cat on project named Person
2. At the top of the fi e, mmed ate y be ow the using namespace System; ne, add the structure
4. F
Not ce how structure data members are accessed Because the DOB member has members of
ts own, you s mp y extend the dot notat on to another eve to access ts members You can
cont nue th s nest ng to as many eve s as you ke, a though t s unusua to go much deeper
than youve done here
5. You can a so n t a ze a the members of Person n one ne Remove the four n t a zat on
nes you entered n step 4 and then change the ne where you create the Person
Person p1 = {"Fred", {10, 3, 1960}};
Can you see what s go ng on here? The data n the bracesca ed an aggregate initializer
prov des data for the n t a zat on of the structure The Person structure conta ns two tems a
String and a Date Therefore, there are two tems n the st Because Date has members of ts
own, ts entr es are a so enc osed n braces
The new Date takes the va ues spec fied n the n t a zer and then cop es t nto the Person
object, overwr t ng the va ues n the Date that s a ready there
7. You can see the configurat on of the Person structure by runn ng the app cat on under contro
of the debugger P ace a breakpo nt n the app cat on at the ne where p1 s created by c ckng n the gray marg n to the eft of the code
8. Press F5 to start the debugg ng sess on
After the app cat on oads, t executes and stops at the breakpo nt You can now use the Loca s pane at the bottom of the w ndow to ook at the structure of the Person type
9. C ck the p us s gn to the eft of p1 n the Loca s pane to expand the structure of Person
Observe that t has Name and DOB members, and f you c ck the p us s gn to the eft of DOB,
you can expand ts structure, as we
10. Press F10 to step through the code unt a the members are n t a zed
11. When youve fin shed, press Sh ft+F5 to stop debugg ng or, on the too bar, c ck the Stop
Debugg ng button
F na y, ets cons der nested structure defin t ons If you dont want to use the Date structure anywhere except ns de your Person structure, you can define Date ns de Person, as shown here
// A Person structure containing a Date structure
value struct Person
{
String ^name;
value struct Date
{
int dd, mm, yyyy;
};
Date DOB;
};
You create Person var ab es and access the r members exact y the same as before The b g d fference s that the Date structure s now a part of Person, so you cant create Date var ab es on the r own
Copying structures
Because structures are va ue types, copy ng them makes a copy of the va ues they conta n Contrast
th s behav or w th c asses, for wh ch copy ng objects resu ts n references be ng cop ed
Person p1;
Person p2;
...
p2 = p1;
// p1's data is copied into p2
MyClass m1;
MyClass m2;
...
m2 = m1;
// m2 and m1 now refer to the same object.
// No data is copied.
Note You cant use a reference type as a member of a structure, because structures arent
garbage-collected; a reference member would have to take part in garbage collection.
Enumerations
An enumerat on (common y referred to as enum) s a set of named nteger constants Enumerat ons
are espec a y su tab e for represent ng types that can take one of a set of fixed va ues such as the
days of the week or the months of the year Enumerat ons are va ue types, and they der ve from
theabstract System::Enum c ass, wh ch n turn der ves from System::ValueType
fo ow ng structure defin t on
// The Weekday enum definition
public enum class WeekDay
{
Monday, Tuesday, Wednesday, Thursday, Friday,
Saturday, Sunday
};
The enum class keywords start an enumerat on defin t on, and you not ce that, once aga n,
enums are defined s m ar y to c asses The body of the enumerat on s enc osed n braces and
fin shes w th a sem co on The use of the enum and class keywords nd cates to the comp er
that th s s a va ue type and not a trad t ona C++ enumerat on
The enumerat on tse f cons sts of a comma-separated set of names, each of wh ch represents
an nteger constant
3. You create enumerat on var ab es the same as you create any other type To create and n t a -
ze a WeekDay object, add the fo ow ng nes to the main funct on of your app cat on
// Create a WeekDay
WeekDay w = WeekDay::Monday;
As w th structures, the code doesnt use the gcnew operator An enumerat on var ab e of type
WeekDay has been created on the program stack, and you access t d rect y as w Not ce how
the enumerat on var ab e s n t a zed w th one of the members of the enumerat on Th s syntax s how you n t a ze enumerat on var ab es and how you can change the r va ues ater on
Note In C++/CLI, unlike in standard C++, enumeration members must be qualified with the name of their type. It is an error to just say Monday rather than
WeekDay::Monday.
The va ue 0 shou d be pr nted Each of the named constants mak ng up the enumerat on
represents an nteger va ue By defau t, these va ues start from 0 and ncrease by one for each
subsequent member of the enumerat on You can test th s output by chang ng the va ue that
you n t a y ass gned to w, for examp e, WeekDay::Saturday When you run the code aga n, the
va ue 5 shou d pr nt
You must cast the enumerat on to an int n order to be ab e to pr nt t; you w
you try to pr nt the enumerat on w thout cast ng t
get an error f
as ts numer c va ue You can do th s us ng the Format member of the Enum base c ass, as n
the fo ow ng examp e
String ^s = Enum::Format(WeekDay::typeid, w, "G");
Console::WriteLine("The day is {0}", s);
Note Ensure that you qualify your enumeration with either public or private. If you dont,
you will get an error (C2664) when you try to use Enum::Format. This is because the new
C++ standard (C++11, which this version of Microsoft C++ supports) has a new enumeration
type; if the compiler does not see public or private on an enumeration declaration, it assumes that you have declared a C++11 enumeration.
If convert ng between ntegers and enumerat ons were a owed, t wou d be poss b e to put nva d
va ues nto the enumerat on If you do want to convert between ntegers and enumerat on va ues, you
need to use an exp c t cast to nform the comp er as to what you want to do, such as n the fo ow ng
examp e
int day = static_cast<int>(w);
You can a so use a cast to go the other way, from nteger to enumerat on, but that snt good
pract ce
You dont have to re y on the defau t numer c va ues that are ass gned to the enumerat on members Suppose that you want the nteger equ va ents of the weekdays to range from 1 through 7
nstead of 0 through 6; s mp y ass gn 1 to the Monday member, as shown here
public enum class WeekDay
{
Monday = 1, Tuesday, Wednesday, Thursday, Friday,
Saturday, Sunday
};
The enumerat on now starts w th 1, and because you havent g ven any other va ues for the rema n ng members, they are numbered 2 through 7
If you want, you can g ve a comp ete y d scont nuous ser es of va ues for the enumerat on members, as n th s examp e
public enum class StatusCodes
{
OK=0, FileNotFound=2, AccessDenied=5, InvalidHandle=6,
OutOfMemory=8
};
a Monday!");
a Tuesday!");
a Wednesday!");
You are a owed to use an enumerat on var ab e as a sw tch contro var ab e because ts bas ca y
an nteger L kew se, you can use the names of enumerat on members as sw tch case abe s because
theyre a so ntegers The examp e code has cases for Monday through Wednesday; everyth ng e se s
hand ed by the defau t case Remember to put the break statements n after the code for each case,
or the app cat on wont behave as you expect
Quick reference
To
Do this
Create a structure.
n t a ze structure members.
CHAPTER 10
Operator overloading
After comp et ng th s chapter, you w
be ab e to
ouve a ready seen how to construct c asses and structures, prov de member funct ons n your
types, and use these funct ons n app cat ons In th s chapter, youre go ng to find out about a
spec a category of member funct ons ca ed over oaded operator funct ons, w th wh ch you can add
extra funct ona ty so that your types can be used more natura y and ntu t ve y
Note If youve encountered operator overloading in C++ before, you will find that there
are many similarities when using C++/CLI. There are also a number of differences, so read
carefully!
159
Rules of overloading
Severa ru es app y when over oad ng operators The prob em s that you can mp ement operators to
mean whatever you ke, so some ru es are needed to mpose a few m ts and to prevent creat ng an
mposs b e job for the comp er
You cannot define any new operators Even f you th nk that %% wou d make a neat new
operator, you cant add t
You cant change the arity, the number of operands taken by an operator You m ght th nk
t wou d be rea y usefu to create a unary / operator, but the d v s on operator a ways has to
have two operands
You cant change the precedence or assoc at v ty of operators So, * (mu t p cat on) a ways
takes precedence over + (add t on), regard ess of what they are actua y mp emented to mean
for a type
Overload
2. At the top of the Over oad cpp fi e, mmed ate y be ow the using namespace System; ne, add
Th s s mp e struct s the one you use throughout these exerc ses It s mp y wraps an int and
then prov des a constructor for creat ng and n t a z ng IntVal objects and a get funct on for
access ng the data member Chapter 9, Va ue types, exp a ns that the keyword value makes
IntVal a NET va ue type rather than a trad t ona C++ structure
3. Create three IntVal objects, rep ac ng the body of the main funct on w th the fo ow ng code
IntVal one(1);
IntVal two(2);
IntVal three;
be n t a zed to zero
4. Try add ng one and two and ass gn ng the resu t to three, fo owed by a WriteLine statement to
pr nt the va ue of three
three = one + two;
Console::WriteLine(three.getVal());
When you bu d the app cat on, you get an error (C2676), nform ng you that the comp er
cant find a + operator that works w th your objects
5. Imp ement the + operator for IntVal by add ng the fo ow ng funct on to the struct defin t on,
Lets ana yze th s funct on An over oaded operator s represented by a funct on whose name
starts w th operator, wh ch a so has the operator symbo appended to t So, the == operator
wou d be represented by a funct on ca ed operator==, the > operator by operator>, and so
on
When the comp er sees the code
one + two
Thus, a b nary operator (one that takes two operands) s represented by a member funct on that takes one argument, the r ght-hand s de of the + operat on A unary operator (one
that takes a s ng e operand, such as the n 1) s represented by a funct on that takes no
arguments
Now, ets ook at how the operator s mp emented The resu t of one + two s not one or two,
but a new va ue that represents the r sum In the code, therefore, we create a new object that
s n t a zed w th the sum of the two va ues and return t
6. Bu d the app cat on aga n
You shou d find that the comp at on s successfu because the comp er can find a + that
works w th IntVal objects If you run the app cat on, you shou d see the va ue 3 pr nted out
162Microsoft Visual C++/CLI Step by Step
Now that youve seen how to mp ement add t on, t shou d be easy for you to mp ement the
other ar thmet c operators Indeed, because th s c ass represents a s mp e nteger va ue, you probab y
shou d mp ement them so that they are cons stent w th the behav or of ntegers
Tip The last sentence in the previous paragraph introduces a very important point: It is
up to you to define all the operators that make your type work properly. See the section
Guidelines for providing overloaded operators at the end of the chapter for more details.
You can eas y add an over oad of operator+ that takes an int, such as n the fo ow ng
IntVal operator+(int rhs)
{
IntVal result(value + rhs);
return result;
}
How about th s next examp e? The ru es of bas c add t on d ctate that th s shou d be equ va ent
three = 2 + one;
If you try th s, however, t w not work, because the comp er cannot find a funct on that takes an
int as ts eft operand But you cannot add such a funct on to IntVal, because such funct ons a ways
have to have an object as the r eft operand
The so ut on s to create a stat c operator over oad n the IntVal c ass, and you wou d do th s for
any b nary operator that s symmetr ca (for examp e, you wou d expect a == 3 to be the same as
3== a)
Th s exerc se shows you how to add a stat c add t on operator to the IntVal c ass
1. Cont nue us ng the project from the prev ous exerc se
2. Add a ne to the main funct on that tr es to use an int as the eft operand Ver fy that t
doesnt comp e
three = 2 + one;
Remember that stat c members be ong to a c ass (or structure) as a who e rather than to any
one object Th s means that they arent assoc ated w th an object, and so they need to be
passed to both operands
If you want, you can mp ement three over oads of the stat c operator, one for (IntVal, IntVal),
one for (IntVal, int), and one for (int, IntVal), and not have the non-stat c vers on at a But, t
turns out that there s a much neater so ut on, wh ch you w see n the exerc se that fo ows
th s one
4. Add the fo ow ng funct on to the struct, p ac ng t after the getVal funct on
static operator IntVal(int v)
{
return IntVal(v);
}
Th s next exerc se shows you how the convers on operator makes t poss b e to use a s ng e operator+ funct on that works w th a comb nat ons of IntVal and int
1. De ete any ex st ng operator+ funct ons and rep ace them w th th s s ng e one
static IntVal operator+(IntVal lhs, IntVal rhs) {
IntVal result(lhs.value + rhs.value);
return result;
}
Th s funct on adds two IntVals, but t a so copes w th an int as e ther the r ght or eft operand
because weve now nstructed the comp er that t can convert between int and IntVal
164Microsoft Visual C++/CLI Step by Step
After the app cat on oads, t executes and stops at the breakpo nt At th s po nt, scro up and
p ace another breakpo nt at the first ne of the operator+ funct on
5. Press F11
Th s br ngs you to the operator+ funct on at the breakpo nt At the bottom of the w ndow, n
the Loca s pane, ook at the va ues Observe that both lhs and rhs are IntVals, show ng that the
int has been converted for you
You can see thatprov ded that your types mp ement the correct constructors and convers on
operatorsyou can somet mes use one operator over oad to perform a fam y of operat ons
6. When you are done, d scont nue the debugg ng sess on e ther by press ng the dark-red
square on the Debug too bar, by c ck ng Stop Debugg ng on the Debug menu, or by press ng
Sh ft+F5
1. Us ng the same project as n the prev ous exerc ses, find the operator+ funct on n your code
The funct on fo ows the same pattern as the operator+ It s a stat c member of the IntVal
structure, but th s t me t returns a Boolean, just as youd expect a og ca operator to do, and
tmakes ts dec s on based on the nterna structure of ts two operands
2. Add some test code to main to test the new operat on
if (three == 3)
Console::WriteLine("All is OK");
else
Console::WriteLine("Something is very wrong!");
3. Bu d and run the app cat on to ver fy that the operator s work ng as you expect
4. If you mp ement equa ty you need to mp ement nequa ty, as we , so add a defin t on for
operator!= to IntVal
static bool operator!=(IntVal lhs, IntVal rhs) {
return !(lhs == rhs);
}
Not ce how th s s mp emented t uses operator== to compare the two objects and then
uses the og ca NOT operator to negate the resu t De egat ng the compar son to operator==
rather than compar ng the nterna s of the objects themse ves s not on y s ght y ess typ ng,
but f the nterna structure of IntVal were to change, you on y have to change the operator==
funct on and you have automat ca y updated operator!=, as we
5. Add some test code for th s new operator
if (three != 3)
Console::WriteLine("Something is wrong!");
else
Console::WriteLine("Inequality working OK");
s work ng correct y
The other og ca operators (<, <=, >, and >=) can be over oaded n a s m ar way, and you can
make use of the same shortcut when mp ement ng them
What is equality?
Dec d ng whether to mp ement == and != depends on the type youre wr t ng, and t m ght
not be a s mp e dec s on For some types the cho ce s obv ous cons der a Point type that has
x and y coord nates In th s case, two Points are equa f the r x and y members have the same
va ue
What about a Currency c ass that has a va ue and a currency type? You m ght say that two
Currency objects are the same f both the va ue and the currency are dent ca L kew se, you
m ght dec de that two objects are the same f the r va ues are the same when converted to a
common base currency such as do ars or Euros Both approaches are equa y va d; ts up to
you to choose one and document t
There m ght a so be c asses for wh ch any not on of equa ty s art fic a Cons der a Bank
Account c ass what wou d equa ty mean? Two accounts cant be comp ete y dent ca because
they have d fferent, un que account numbers You m ght choose someth ng that counts as
equa ty (such as hav ng the same ba ance) but there s no obv ous mean ng You m ght we
dec de that equa ty s not mean ngfu for such types
As a fina po nt, remember that test ng for equa ty can pose prob ems for float ng-po nt
va ues It s we known that computat ons on these types can ntroduce round ng errors n the
fina dec ma p aces; thus, two va ues wh ch shou d be dent ca m ght not test as equa
One way around th s s to define such va ues as be ng equa f they are w th n a to erance; for
examp e
if (Math::Abs(value1 - value2) < 0.00001)
// they are equal
else
// they are not
The Math::Abs funct on s a stat c member of the Math c ass that returns the abso ute va ue
of ts operand
Implementing Equals
A types n NET u t mate y nher t from the System::Object c ass Th s c ass prov des severa funct ons
that a NET types nher t, and the one that s part cu ar y re evant to our d scuss on of equa ty s the
Equals funct on
W th Object::Equals, types can prov de a way to compare content, as opposed to compar ng references Th s s the same job that youve been do ng by mp ement ng the == operator, but t works
for anguages that dont support operator over oad ng Th s means that f your types are go ng to be
used from other NET anguages, you need to mp ement the Equals funct on
In th s exerc se, you w
1. Cont nue us ng the same project Add the fo ow ng funct on to the end of the IntVal structure
defin t on
virtual bool Equals(Object ^other) override
{
IntVal ^obj = dynamic_cast<IntVal^>(other);
if (obj == nullptr)
return false;
return value == obj->value;
}
Th s funct on s more comp ex than the others youve ooked at, so you m ght want to comp e
the code to ensure that you havent made any cod ng errors Lets exam ne the code ne by
ne The funct on s nher ted from System::Object, so you need to use both the virtual and
override mod fiers to show that you are overr d ng a base c ass v rtua funct on Equals takes a
hand e to an Object as ts argument because t s nher ted by a c asses and so can be used to
compare any type at a
The first th ng you need to do s to use dynamic cast to convert the Object hand e nto an
IntVal hand e
Note dynamic cast is a C++ casting mechanism that performs a cast at run time,
returning a nullptr if the types dont match.
If the hand e passed n wasnt an IntVal, the cast w return nu You know that two objects of
d fferent types cant be equa , so you can return false mmed ate y If the resu t s not nu , we
have an IntVal Compar son s then s mp y a case of compar ng the fie ds of the two objects to
see f they are the same
2. Test the Equals funct on by creat ng some IntVal objects and check ng f they are equa
IntVal four(4), anotherFour(4), five(5);
if (four.Equals(anotherFour))
Console::WriteLine("All is OK");
else
Console::WriteLine("Something is wrong...");
if (four.Equals(five))
Console::WriteLine("Something is very wrong!");
else
Console::WriteLine("All is OK");
You m ght wonder how an IntVal object s turned nto an Object hand e n the ca to Equals
If the comp er sees a va ue type be ng used where a reference type s wanted, t automat ca y wraps t n an object wrapper, a process ca ed boxing, wh ch s d scussed n more deta n
Chapter 22 Work ng w th unmanaged code
3. Bu d and run the app cat on to ensure the resu ts are what you expect
The stat c funct on takes a s ng e IntVal as ts argument, ncrements ts va ue, and then
returns t
2. Test out the operator n code, such as the fo ow ng
IntVal first(3);
IntVal next = ++first;
// pre-increment
Console::WriteLine("pre-inc, next = {0}, first = {1}",
next.value, first.value);
next = first++;
// post-increment
Console::WriteLine("post-inc, next = {0}, first = {1}",
next.value, first.value);
The fo ow ng output d sp ays, show ng that your operator s work ng n both pre and postncrement s tuat ons
pre-inc, next = 4, first = 4;
post-inc, next = 4, first = 5;
The var ab e first started w th the va ue 3 The pre- ncrement changed t to 4 and then used t
n the ass gnment The post- ncrement d d the ass gnment and then ncreased the va ue
After you have mp emented the ncrement operator, t w
same way
You can see how objects and the dot operator have been rep aced by hand es and ->, and objects
are created by us ng gcnew Apart from that, the code s substant a y the same
Quick reference
To
Do this
CHAPTER 11
Exception handling
After comp et ng th s chapter, you w
be ab e to
Recogn ze the d fferent types of except ons that can be used n C++/CLI
ow that you know how to construct c asses and va ue types and use them n programm ng, th s
chapter ntroduces you to except on hand ng, a powerfu way of manag ng errors w th n C++
app cat ons
Note The & (ampersand character) denotes a reference in standard C++, in the same way
that % denotes a tracking reference in C++/CLI.
175
A though th s s a tr ed-and-tested way of pass ng status nformat on around, t suffers from severa
drawbacks
If youre deep w th n n a ser es of nested ca s, you must set each status flag and back out
manua y
Its very d fficu t to pass back status nformat on from someth ng that doesnt take arguments
or return a va ue
Except ons prov de an a ternat ve error-hand ng mechan sm, wh ch g ves you three ma n advantages over trad t ona return-va ue error hand ng
Exceptions cant be ignored If an except on snt hand ed at some po nt, the app cat on
w term nate, wh ch makes except ons su tab e for hand ng cr t ca errors
Exceptions dont have to be handled at the point where the exception occurs An error
can occur many eve s of funct on ca deep w th n an app cat on, and there m ght not be a
way to fix the prob em at the po nt at wh ch the error occurs Except ons make t poss b e for
you to hand e the error anywhere up the ca stack (See the upcom ng s debar The ca stack
and except ons )
Exceptions provide a useful way to signal errors when a return value cant be
used There are two part cu ar p aces n C++ where return va ues cant be used constructors
dont use them, and over oaded operators cant have the r return va ue over oaded to use for
error and status nformat on Except ons are part cu ar y usefu n these s tuat ons because
they g ve you a means to s destep the norma return-va ue mechan sm
In NET, except ons have one other s gn ficant advantage They can be used across anguages
Because except ons are part of the under y ng M crosoft NET Framework, ts poss b e to throw an
except on n C++/CLI code and catch t n M crosoft V sua Bas c NET, someth ng that snt poss b e
outs de the NET env ronment
176Microsoft Visual C++/CLI Step by Step
As s the case w th any other error mechan sm, you tend to tr gger except ons by mak ng errors n
your code However, you can a so generate except ons yourse f f necessary, as you see short y
Its easy to see that th s code s go ng to cause a d v de-by-zero error, and when t s executed, you
see the resu t shown n the fo ow ng screen shot
You can see that the d v de-by-zero has resu ted n an except on be ng generated Because I
d dnt hand e t n the code, the app cat on has been term nated, and the fina output never makes
t to the screen Not ce the form of the standard message t nforms you as to what happened (a
System::DivideByZeroException error), presents an error message, and then g ves you a stack trace that
d rects you to where the error occurred ( n th s case, n the main funct on at ne 13 n the Except onTest cpp fi e)
System::DivideByZeroException denotes the k nd of object that was passed n the except on A ot of
except on c asses are prov ded n the System namespace, and ts a so ke y that you make up your
own based on the System::Exception base c ass, as you see ater n the chapter
Exception types
Except on hand ng s s ght y comp cated n that you m ght encounter three d fferent types of except on hand ng when us ng C++/CLI trad t ona C++ except ons, C++/CLI except ons, and M crosoft
W ndows Structured Except on Hand ng (SEH) Trad t ona C++ except ons form the bas s of a except on hand ng n C++ C++/CLI adds the ab ty to use managed types (for examp e, ref c asses and
value types) n except ons, and you can m x them w th trad t ona except ons C++/CLI a so extends
except on hand ng by add ng the concept of a finally b ock, wh ch I d scuss n the sect on The finally
b ock ater n the chapter The th rd sort of except on hand ng, SEH, s a form of except on hand ng
bu t n to W ndows operat ng systems that s ndependent from C++ I wont ta k any more about SEH
here, except to note that you can nteract w th t from C++
Throwing exceptions
Lets start our exp orat on of except ons by d scuss ng how to generate, or throw, them You end up
generat ng far more except ons by acc dent than by des gn, but you need to know how to generate
your own when errors occur n your app cat on
How do you know what to throw? There are a arge number of except on c asses n the System
namespace, a of wh ch der ve from Exception A number of those you common y encounter are
sted n the fo ow ng tab e You shou d be ab e to find the except on c ass to su t your purposes, and
f you cant, ts a ways poss b e to der ve your own except on c asses from System::Exception
178Microsoft Visual C++/CLI Step by Step
3. Insert code to test the behav or by add ng the fo ow ng code to the main funct on
Console::WriteLine("Throw Test");
Console::WriteLine("Calling with a=3");
func(3);
Console::WriteLine("Calling with a=0");
func(0);
Console::WriteLine("All done");
The code ca s the funct on tw ce, once w th a va d va ue and once w th 0, wh ch shou d tr gger the except on
4. Comp e and run the app cat on, and you shou d see someth ng s m ar to the fo ow ng
screen shot
The app cat on has ca ed the funct on once w thout nc dent, but the second ca has tr ggered an
except on As before, you get a message and a stack trace Th s t me the message s the str ng used to
n t a ze the except on object and the stack trace has two eve s, show ng that the except on was tr ggered at ne 10 n the func funct on, wh ch was ca ed from the main funct on at ne 20
Note The precise line number you see reported in the exception stack trace depends on
exactly how you typed in and formatted your code.
Handling exceptions
Now that youve seen how to generate except ons, ets move on to hand ng them
catch(TypeTwo ^two)
{
// handle this exception
}
Code that you suspect m ght fa s enc osed n a try b ock that s fo owed by one or more hand ers n the form of catch b ocks Each catch b ock ooks a tt e ke a funct on defin t on, w th catch
fo owed by a type n parentheses, wh ch represents the type that w be caught and processed by the
catch b ock In the preced ng code, the first catch b ock hand es except ons tagged w th a TypeOne^
object, whereas the second b ock hand es those tagged w th a TypeTwo^ object
Note try and catch blocks form a single construct. You cant have a try block without at
least one catch block, you cant have a catch block without a try block, and you cant put
anything in between them.
You can cha n as many catch b ocks together as there are except on types to catch, as ong as you
have at east one
The fo ow ng exerc se shows you the bas cs of hand ng except ons, us ng the examp e from the
prev ous exerc se as a bas s
1. Cont nue us ng the project from the prev ous exerc se
2. Mod fy the main funct on to ook ke the fo ow ng
Console::WriteLine("Throw Test");
try
{
int a = 3;
Console::WriteLine("Calling with a=3");
func(a);
Console::WriteLine("Calling with a=0");
a = 0;
func(a);
}
catch(System::ArgumentException ^ex)
{
Console::WriteLine("Exception was {0}", ex);
}
Console::WriteLine("All done");
The ca s to the funct on are enc osed n a try b ock, wh ch s fo owed by a s ng e catch b ock
When the second ca to the funct on fa s, the except on-hand ng mechan sm takes over It
cant find a hand er n the funct on where the error or g nated, so t wa ks one eve up the ca
stack and comes out n the try b ock
In a s m ar way, you cou d use StackTrace to retr eve and pr nt the stack trace nformat on
Suppose that a DivideByZeroException s thrown You m ght expect t to be caught by the second
catch b ock, but t w , n fact, be caught by the first one Th s s because accord ng to the nher tance h erarchy, a DivideByZeroException s an ArithmeticException, so the type of the first catch b ock
matches To get the behav or you expect when us ng more than one catch b ock, you need to rank
the catch b ocks from most spec fic to most genera
Tip The compiler will give you warning C4286 if you have the catch blocks in the wrong
order. This works for both managed and unmanaged code.
So, f you just want to catch a ar thmet c except ons, you can s mp y put n a hand er for
ArithmeticException, and a except ons from der ved c asses w be caught In the most genera
case,you can s mp y add a hand er for Exception, and a managed except ons w be caught
fo ow ng c ass defin t on
ref class Test
{
String ^str;
public:
Test(String ^s)
{
if (s == nullptr || s == "")
throw gcnew System::ArgumentException("Argument null or blank");
else
str = s;
}
};
The ref keyword makes th s c ass managed, and th s managed c ass has one s mp e data member, a hand e to a managed String At construct on t me, th s hand e must not be nu or po nt
to a b ank str ng, so the constructor checks the hand e and throws an except on f the test fa s
If the hand e passes the test, construct on cont nues
NoteThe nullptr keyword represents a null value for a handle; it must be used
where a null value is required. This is in contrast to standard C++, in which you can
use a numeric 0 to represent a null pointer.
Not ce that the ca to gcnew s enc osed n a try b ock If someth ng s wrong w th the String
hand e (as t s here), the Test constructor w throw an except on that w be caught by the
catch b ock
4. Bu d and run the app cat on, and you w
// Do something
}
catch(SomeException ^ex1)
{
Console::WriteLine("Exception: {0}", ex1->Message);
}
}
catch(OtherException ^ex2)
{
Console::WriteLine("Exception: {0}", ex2->Message);
}
If an except on occurs w th n the nner try b ock that s of type SomeException^, t w be hand ed
by the nner catch b ock and execut on w cont nue after the end of the nner catch b ock, as usua
The outer catch b ock w not be executed n th s case because the error has a ready been adequate y
hand ed
If an except on occurs w th n the nner try b ock that s of type OtherException^, t wont be
hand ed by the nner catch b ock, so t w be passed to the outer try and catch construct, where t s
processed by the outer catch b ock
Note You can nest try and catch constructs to several levels, but its unusual to go more
than two levels deep because it can overcomplicate the structure of the code.
Rethrow ng an except on means just thathand ng an except on n a catch b ock and then throwng t aga n so that t can be hand ed somewhere e se The fo ow ng exerc se shows how to catch an
except on and rethrow t
1. Create a new CLR Conso e App cat on project named Rethrow
2. Immed ate y after the using namespace System; ne and mmed ate y before main, add the fo -
ow ng funct on defin t on
void func(int a)
{
try
{
if (a <= 0)
throw gcnew ArgumentException("Aaargh!");
}
catch(ArgumentException ^ex)
{
Console::WriteLine("Exception caught in func()");
}
}
Th s funct on s bas ca y the same s mp e funct on to wh ch you were ntroduced at the start of
the chapter It throws a System::ArgumentException when t has passed a negat ve argument
The d fference here s that the except on s be ng caught w th n the funct on
If you run th s code, you find that the except on s caught oca y n func and the catch b ock
n main doesnt execute
4. Mod fy the defin t on of func so that t rethrows the except on after hand ng t
void func(int a)
{
try
{
if (a <= 0)
throw gcnew ArgumentException("Aargh!");
}
catch(ArgumentException ^ex)
{
Console::WriteLine("Exception caught in func()");
throw;
// rethrow the exception
}
}
Us ng throw w thout an argument rethrows the current except on, and t can be used n th s
way on y w th n a catch b ock At th s po nt, the runt me goes off ook ng for another hand er,
wh ch means mov ng up the ca stack to the main funct on, where the except on s caught a
second t me
5. Bu d and run th s app cat on
The Except on caught n func() and Except on caught n ma n() messages pr nt, demonstrat ng that the except on has been hand ed tw ce
Note that you dont have to rethrow the same except on; ts qu te usua to catch one type of except on, hand e t, and then rethrow an except on of another type You see an examp e of th s n the
sect on Creat ng your own except on types ater n th s chapter
catch b ock
Console::WriteLine("Throw Test");
try
{
int n = 3;
Console::WriteLine("Calling with n=3");
func(n);
Console::WriteLine("Calling with n=0");
n = 0;
func(n);
}
catch(System::ArgumentException ^ex)
{
Console::WriteLine("Exception was {0}", ex);
}
finally
{
Console::WriteLine("This is the finally block");
}
Console::WriteLine("All done");
If you try execut ng the code, you find that the finally b ock s executed after the catch b ock
3. Mod fy the main funct on so that the second ca doesnt cause an except on, e ther by chang-
ng the va ue or by comment ng t out When you run the app cat on aga n, you see that the
finally b ock s st executed, even though there was no error
The purpose of th s b ock s to ensure that f you do someth ng n the try b ocksuch as open ng a
fi e or a ocat ng some memoryyou be ab e to t dy up whether an except on occurs or not because
the finally b ock s a ways executed when execut on eaves a try b ock Th s construct g ves you a way
to c ean up what m ght otherw se requ re dup cate code
If an except on doesnt match the first catch b ock, t w be caught by the second one, no matter what type t s The prob em s that you ose any nformat on about the except on, because the
catch(...) b ock doesnt have an argument
Note Even though you cant tell what kind of exception you are handling inside a catch()
block, if you rethrow from within the block, a properly typed object will be thrown to handlers higher in the call stack.
If you want th s funct ona ty when us ng C++/CLI, use a catch b ock that has an Exception^ as ts
argument, wh ch w catch any managed except on object
Th s custom except on c ass s a managed c ass that nher ts from System::Exception, and t
extends Exception by add ng a s ng e fie d to ho d an error number The c ass constructor takes
a message and a number, and passes the message str ng back to the base c ass
Note Ive made the errNo field public. Although youre normally advised to make all
data members of classes private, you can make a case for having public data members in certain circumstances. After youve created an Exception object and passed it
back to the client, do you care what the client does with it? Exceptions are fire and
forget objects, and youre normally not concerned with the integrity of their state
after they leave your code in a throw statement.
3. Add the fo ow ng funct on defin t on mmed ate y after the c ass defin t on
void func(int a)
{
try
{
if (a <= 0)
throw gcnew ArgumentException("Argument <= 0");
}
catch(System::ArgumentException ^ex)
{
Console::WriteLine("Caught ArgumentException in func()");
throw gcnew MyException(ex->Message, 1000);
}
}
The funct on checks ts argument and throws a System::ArgumentException f t finds a negat ve va ue Th s except on s caught oca y, and a message s pr nted Now, I dec de that I rea y
want to hand e the except on e sewhere, so I create a new MyException object and throw t,
n t a z ng t w th the message from the or g na ArgumentException
4. Test the except on hand ng by ca ng the funct on n the app cat on s main rout ne
int main()
{
Console::WriteLine("Custom Exceptions");
try
{
func(0);
}
catch(MyException ^ex)
{
Console::WriteLine("Caught MyException in main()");
Console::WriteLine("Message is '{0}'", ex->Message);
Console::WriteLine("ErrNo is {0}", ex->errNo);
}
return 0;
}
The comp er ra ses an error on the ast ne, comp a n ng that t cant convert a Vehicle^ to a Car^
The prob em s that a Vehicle hand e cou d po nt to any object der ved from Vehicle such as a Truck
or a Bus Imp c t y cast ng from a Car to a Vehicle s fine because a Car s a Vehicle; go ng the other
way doesnt work because not every Vehicle s a Car One way around th s ssue s to use the safe cast
construct, such as n the fo ow ng
try
{
Car ^pc2 = safe_cast<Car^>(pv);
}
catch(System::InvalidCastException ^pce)
{
Console::WriteLine("Cast failed");
}
At run t me, safe cast checks the object on the other end of the hand e to see f t has the same
type as the object to wh ch youre try ng to cast If t does, the cast works; f t doesnt, an Invalid
CastException s thrown
Note Experienced C++ programmers will realize that safe cast is very similar to the
dynamic cast construct supported by standard C++. The difference is that safe cast throws
an exception if the cast fails, whereas dynamic cast returns a null value.
Note In .NET you should throw exception objects that derive from System::Exception.
Standard C++ allows you to throw and catch any kind of value, such as ints and doubles. If
you do this and the exception is thrown to non-C++ code, your value will be wrapped in a
RuntimeWrappedException object.
In the fina examp e n th s chapter, you w create a C++ c ass n a dynam c- nk brary (DLL) and
then use the c ass n a V sua Bas c NET app cat on
Note You will need to have Visual Basic.NET installed to complete the second part of this
example.
1. Start V sua Stud o 2012 and open a new V sua C++ project Th s t me, choose a C ass L brary
project from the CLR sect on th s s used when you want to create a DLL rather than an EXE I
ca ed the project MyC ass; you can name t what you ke, but make a note of the name
You find that youve created a project that defines a namespace ca ed MyClass, conta n ng
a s ng e c ass ca ed Class1 Its th s c ass that you ed t, add ng a method that can be ca ed
from a V sua Bas c c ent
2. The project w
conta n a number of fi es, among them MyC ass h and MyC ass cpp, wh ch are
used to ho d the defin t on and mp ementat on of the Class1 c ass Open MyC ass h and add
the Test funct on so that t ooks ke the fo ow ng code
// MyClass.h
#pragma once
using namespace System;
namespace MyClass
{
public ref class Class1
{
public:
void Test(int n)
{
if (n < 0)
throw gcnew ArgumentException(
"Argument must be positive");
}
};
}
The Test method shou d ook fam ar by now t s mp y checks ts argument and throws an
except on f ts ess than 0
3. Bu d the project
You end up w th a DLL ca ed MyC ass d be ng created n the projects Debug d rectory
4. C ose the project (by c ck ng C ose So ut on on the F e menu) and create a new V sua Bas c
Conso e App cat on project named Tester Before you can use the DLL you just created, you
have to add a reference to t to the project To do so, open So ut on Exp orer (us ng the So ut on Exp orer tem on the V ew menu f t snt v s b e) and r ght-c ck the project name
5. On the shortcut menu that appears, c ck Add Reference In the Reference Manager d a og box
that opens, c ck Browse and search for the DLL you bu t n step 3 Ensure that ts added to
the Se ected Components pane and then c ck OK
6. Add the code to the project Open Modu e1 vb and ed t the Main funct on so that t ooks ke
the fo ow ng code
' Application to demonstrate cross-language exception handling
Imports [MyClass]
Module Module1
Sub Main()
Dim obj As New Class1()
Try
obj.Test(-1)
Catch ex As ArgumentException
Console.WriteLine("Exception: " & ex.Message)
End Try
Console.WriteLine("All done")
End Sub
End Module
The first ne mports the MyClass namespace nto the app cat on Th s ne does the same
job as using namespace does n C++, so you dont have to fu y qua fy the name Class1 when
t appears The first ne n the Main funct on creates a new Class1 object; th s s equ va ent
to creat ng an object n C++ by us ng gcnew The ca to the Test funct on s enc osed n a Try
and Catch construct, and you can see the s m ar ty between the way except ons are hand ed
n V sua Bas c and C++ The ma n d fference s that n V sua Bas c, the Catch b ocks are ns de
the Try b ock
194Microsoft Visual C++/CLI Step by Step
Note Even if you dont know Visual Basic, it should be obvious that the structure
of the code is quite similar to C++/CLI, and you are using exactly the same .NET
Framework types.
Pass ng 1 through as the argument tr ggers the except on, and you shou d see the message
pr nted out n the Catch b ock
Quick reference
To
Do this
Use the base c ass of the except ons that you want to
catch n the catch b ock; for examp e, ArithmeticException
w catch DivideByZeroE xception and severa others.
CHAPTER 12
be ab e to
h s chapter concerns tse f w th data structures You earn about arrays and other co ect on
c asses, and you earn how to use them n your app cat ons In the first part of the chapter,
youre go ng to earn about two sorts of arrays the nat ve arrays prov ded by the C++ anguage, and
the M crosoft NET managed arrays, wh ch use funct ona ty nher ted from the NET Framework
The second part of the chapter ooks more w de y at the range of co ect on c asses prov ded by
the NET Framework, d scuss ng the r character st cs and show ng you how and when to use them The
chapter conc udes w th a br ef ntroduct on to the STL/CLR brary
TradArray
197
2. Open the source fi e Trad cpp and ed t the main funct on to match the fo ow ng
const size_t SIZE = 10;
int main(array<System::String ^> ^args)
{
Console::WriteLine("Traditional Arrays");
// Create an array
int arr[SIZE];
Console::WriteLine("Size in main: {0}", sizeof(arr));
// Fill the array
for(size_t i=0; i<SIZE; i++)
arr[i] = i*2;
return 0;
}
The first ne dec ares a constant that represents the s ze of the array Us ng symbo c constants
n th s fash on s preferab e to us ng the nteger tera 10 n the code Not on y does t make
exp c t just what the 10 represents, but shou d you want to change the s ze of the array, you
on y have to change the va ue n one p ace
The type size t s a typedef for unsigned int Th s s used where you want to denote s zes,
d mens ons, or quant t es It s good pract ce to use size t rather than int A so note the w despread convent on of us ng cap ta zed names for constants
The array s created by spec fy ng a type, a name, and a s ze enc osed n square brackets ([])
Here, the array s named arr, and t ho ds ten int va ues A arrays are created by us ng the
same syntax, as shown here
// Create an array of six doubles
double arr[6];
// Create an array of two char*'s
char* arr[2];
Heres the first mportant po nt about nat ve arrays after youve created an array, you cant
res ze t, so you need to know how many e ements you requ re before you start If you dont
know how many e ements youre go ng to need, you m ght be better off us ng a NET co ect on, wh ch s d scussed ater n th s chapter
Note The array size has to be known at compile time, so, for example, you cant
ask the user for a value and then use that value to specify an array dimension at
run time. However, its common to create constants, either by using preprocessor
#define declarations or by declaring const variables, and using them to specify array
dimensions.
As you can see from the oop n the preced ng code, array e ements are accessed by us ng
square brackets that conta n the ndex Heres the second mportant po nt about nat ve arrays
ndex ng starts at zero rather than one, so the va d range of nd ces for an array s from zero
to one ess than the s ze of the array In other words, for a 10-e ement array, va d nd ces are
[0] to [9]
3. Add a second oop to pr nt out the arrays contents after fi ng t
// Print its contents
for(size_t j=0; j<10; j++)
Console::WriteLine(arr[j]);
The va ues pr nt, one to a ne, as shown n the fo ow ng screen shot, and you a so see that the
s ze of the array s 40, represent ng 10 ints of 4 bytes each
What happens f you change the range of the second oop so that t tr es to pr nt the e ement
at [10]?
5. A ter the code n the second oop to ook ke the fo ow ng
// Print its contents
for(size_t j=0; j<=10; j++)
Console::WriteLine(arr[j]);
Not ce the ess-than-or-equa -to (<=) cond t on The effect of th s cond t on s to try to pr nt
11 e ements rather than 10 Comp e and run the program, and you shou d see output s m ar
to the fo ow ng
Not ce the random va ue thats been pr nted at the end of the st Heres the th rd mportant
po nt about nat ve arrays bounds arent checked Nat ve arrays n C++ arent objects, and
therefore they have no know edge of how many e ements they conta n Its up to you to
keep w th n the bounds of the array; f you dont, you r sk corrupt ng data or crash ng your
app cat on
youre nstruct ng the comp er to reserve memory arge enough to ho d 10 ntegers and
return you the address as foo When you access an array e ement, youre actua y spec fy ng the
offset from th s address; thus, foo[1] means offset one int from the address foo, and use what
s stored there Th s exp a ns why array ndex ng starts from 0 an ndex of 0 denotes an offset
of zero from the start address, so t means the first e ement
As soon as the comp er has a ocated the space, t works from that po nt forward re at ve to
th s start ng address When you prov de an offset n terms of an array ndex, the comp er generates code to access that p ece of memory And, f you have t wrong and stepped outs de the
bounds of the a ocated memory, you can end up read ng or wr t ng somewhere nappropr ate
A though th s m ght seem dangerousand ndeed, t s n fact, t s somet mes both
des rab e and necessary behav or, for reasons that unfortunate y I have ne ther the t me nor
space to exp a n n proper deta here Try ng to read or wr te off the end of an array s ca ed a
buffer overrun Th s has been the cause of many ser ous bugs n C and C++ app cat ons Some
ma c ous nd v dua s have used these bugs to create attacks aga nst app cat ons, and there are
many we -documented exp o ts that use buffer overruns Too s do ex st to check that app cat ons arent m sbehav ng, but they cant catch everyth ng, and so you have to be very carefu to
check your use of array nd ces
The first argument to the funct on a erts the comp er that the address of an array s go ng to
be passed, wh ch s equ va ent to pass ng a po nter Its very common to see int* used, nstead
The second argument passes the s ze of the array n effect, the amount of memory po nted
to by the first argument The funct on pr nts out the array by us ng the s ze, just as before
3. Ca the funct on from the main rout ne, as shown here
func(arr, 10);
What f the array s ze needs to be changed at some po nt? You can make your code more
robust by ca cu at ng the number of e ements n the array automat ca y by us ng the sizeof
operator, ke th s
func(arr, sizeof(arr)/sizeof(arr[0]));
The sizeof operator returns the s ze of ts argument n bytes, where the argument can be a
var ab e name or a type name Us ng sizeof on an array returns the tota s ze of the array n
bytes, n th s case, 40 bytes When d v ded by the s ze of one e ement4 bytesyoure eft
w th the number of e ements n the array
4. Bu d and run the app cat on
The r ght va ues pr nt out as we as the fact that the array s of s ze 4 bytes Th s reflects the
fact that t s passed to the funct on as a po nter
Initializing arrays
Its poss b e to n t a ze arrays at the po nt of dec arat on, as shown n the fo ow ng syntax fragment
int arr[4] = { 1, 2, 3, 4 };
The va ues to be used for n t a zat on are prov ded as a comma-separated st n braces ({}) on the
r ght s de of an ass gnment; these va ues are known as an aggregate n t a zer The comp er s c ever
enough to figure out how many va ues are n the st, and t w d mens on the array to fit f you dont
prov de a va ue
// Dimension the array automatically
int arr[] = { 1, 2, 3, 4 };
If you g ve a d mens on and then prov de too many va ues, you get a comp er error If you dont
prov de enough va ues, the n t a va ues you g ve w be used to n t a ze the array start ng from e ement zero, and the rema n ng e ements w be set to zero
Multidimensional arrays
Mu t d mens ona arrays n C++ are an extens on of the s ng e-d mens ona var ety The fo ow ng
short exerc se shows how to create and use a two-d mens ona array
1. Create a new CLR Conso e App cat on project named MultiD
2. Open the source fi e Mu t D cpp and add the fo ow ng code to the main funct on
int main(array<System::String ^> ^args)
{
Console::WriteLine("Multidimensional Arrays");
// Create a 2D array
int arr[2][3];
// Fill the array
for(int i=0; i<2; i++)
for(int j=0; j<3; j++)
arr[i][j] = (i+1)*(j+1);
return 0;
}
Observe that a two-d mens ona array s dec ared by us ng two sets of square brackets You
dont put the two va ues ns de one set of brackets, as you do n many other anguages,
and for h gher-order arrays, you s mp y add more sets of square brackets As w th s ng ed mens ona arrays, you have to prov de the s ze at comp e t me, and the nd ces of each
d mens on vary from zero to one ess than the dec ared s ze Array e ements are a so accessed
by us ng two sets of square brackets
3. Pr nt out the array by us ng an extens on of the method for pr nt ng out the e ements of the
Not ce that one row of the array s pr nted on one ne The nner oop pr nts a s ng e
row by us ng repeated ca s to Console::Write After each row has been output, a ca to
Console::WriteLine outputs a new ne
To pass a mu t d mens ona array to a funct on, use two empty sets of square brackets (for examp e,
int arr[][]) and spec fy the d mens on nformat on, as before
Youve prev ous y used the gcnew operator to create NET reference types; the new operator s
used n trad t ona C++ code n a s m ar way to a ocate memory dynam ca y at run t me The
syntax s new, fo owed by the type of the array and then the d mens on enc osed n square
brackets After the array has been created, youre returned a po nter to the start of the array
Po nters work n a s m ar way to hand es, but they use an aster sk (*) nstead of a caret
You can see that dynam c arrays are accessed n exact y the same way as stat ca y a ocated arrays,
us ng the square-bracket notat on Th s use of a po nter w th array notat on under nes the re at onsh p between po nters and arrays, as exp a ned n the s debar How do nat ve arrays work? ear er n
th s chapter
Not ce the ca to delete just before the program ex ts A ocat ng an array dynam ca y n trad t ona C++ doesnt create a managed object, so there s no garbage co ect on assoc ated w th th s array
Therefore, to use memory effic ent y, you must remember to dea ocate memory as soon as youve
fin shed w th the array There are two vers ons of delete one to de ete s ng e objects (delete), and one
for arrays (delete [])
When de et ng an array, you need to use the delete [] vers on If you forget the square brackets,
your app cat on m ght we st run, but accord ng to the standard, the resu t of ca ng s ng e-e ement delete on an array s undefined
Str ct y speak ng, the ca s unnecessary here because a a ocated memory s freed up when the
app cat on ex ts However, n any rea -wor d app cat on, you need to manage your memory carefu y
to ensure that a memory s freed up at an appropr ate po nt
Note After youve called delete on a pointer, you must not use the pointer again, because
the memory it points to is no longer allocated to you. If you try to use a pointer after freeing up the memory it points to, you can expect to get a run-time error.
Not freeing up memory If you dont free up memory when you have fin shed w th t,
you create a memory leak A though th s prob em s norma y the ess ser ous of the two,
t resu ts n an app cat on tak ng up more memory than t needs In extreme cases, the
amount of extra memory consumed by an app cat on can reach the po nt where t beg ns
to nterfere w th other app cat ons or even the operat ng system
Freeing up memory inappropriately In a comp ex app cat on, t m ght not be obv ous where a part cu ar p ece of memory shou d be freed up or whose respons b ty t s to
free t If delete s ca ed too soon and another p ece of code tr es to use the dynam ca y
a ocated array, you can expect a run-t me error The same s true f anyone attempts to
ca delete on the same po nter more than once
A though manua memory a ocat on us ng new and delete makes t poss b e for you to manage memory very prec se y, these two prob ems were the mpetus beh nd the deve opment of
garbage co ectors, wh ch make the system track the use of dynam ca y a ocated memory and
free t up when no one e se s us ng t
Generic types
Before we ta k about the NET array and co ect on c asses, we need to ntroduce the concept of
generic types Th s s a comp ex top c, and we cannot cover t n great depth, but th s sect on prov des
enough deta for you to understand why gener c types are usefu and how they work You w a so
find that you use gener c types far more often than you create them, so I w focus on how to use the
gener c types you w encounter n NET
Perhaps the eas est way to ntroduce gener c types s through an examp e Suppose that you want
to create a c ass that w ho d a st of object hand es When you beg n des gn ng the c ass, you w
soon rea ze that t doesnt matter what type the objects n the st are, as ong as they are ref types
and you can get a hand e to them A st of String^ w work n exact y the same way as a st of
Person^ or a st of Vehicle^ In fact, you can say that your st c ass w work w th T^, where T s any
reference type
Th s s what gener c types g ve you the flex b ty to do You can wr te a c ass n terms of T^, and
on y dec de what T s go ng to be when you use t Here s what a (very) part a defin t on of such a
gener c st c ass m ght ook ke
generic <typename T>
ref class MyList
{
public:
void Add(T obj);
T GetAtIndex(int idx);
...
};
The c ass defin t on beg ns w th the generic keyword, wh ch a erts the comp er that youre start ng
a gener c type The <typename T> then nforms the comp er that T s a type parameter, a p aceho der
that w be fi ed n ater and wh ch must be the name of a type You can then mp ement the c ass n
terms of T, us ng t n member dec arat ons, and for funct on parameter and return types
Note It is possible (and quite common) for a generic type to have more than one type
parameter. For example, a dictionary of key/value pairs will have one parameter for the
keytype and a second for the value type, which would be denoted by <typename K,
typename V>.
To use th s type n code, you need to spec fy to the comp er what T w
name n ang e brackets
be by prov d ng as a type
Th s ne nforms the comp er that we want a st of String^, and the comp er w ensure that the
object w on y work w th String^ Any attempt to add another type resu ts n a comp e-t me error
The types created from a gener c type by spec fy ng a type parameter are ca ed constructed types
Note When this code is compiled, a generic version of the class is added to the assembly,
and constructed types are created at run time, as needed. This is important because it
means that it is not necessary to know when compiling the original MyList<T> code what
types it will be used with at run time.
Managed arrays
The NET Framework brary conta ns an array c ass that prov des a managed equ va ent of a standard
C++ array but w thout the d sadvantages A managed array s an object that s a ocated on the managed heap and subject to the norma garbage-co ect on ru es
Note Unlike standard C++ arrays, indexing is not just a way of specifying an offset from an
address.
Creat ng a managed array s qu te d fferent from creat ng a standard C++ array You dec are a
managed array by us ng the array keyword, as n the fo ow ng examp es
array<int> ^arr1;
array<double, 2> ^arr2;
array<Person^> ^arr3;
Observe that a of these are dec ared as hand es Th s s because an array s a managed object, and
you a ways nteract w th arrays through hand es So, arr1 s a hand e to a 1D array of ntegers; arr2 s a
hand e to a 2D array of doub es; and arr3 s a hand e to an array of Person hand es
NoteThe <> syntax indicates that the array is a generic type. The array class is written so
that it can represent an array of any type of object, and you specify the type it is to contain
in angle brackets at the time of declaration.
The genera syntax for dec arat on s
array<type, rank> handle_name;
where rank s the number of d mens ons (a though for a 1D array, you can om t the rank) So, we
cou d dec are some arrays as fo ows
array<int> ^intArray = gcnew array<int>(5);
array<String^> ^stringArray = gcnew array<String^>(10);
The first ne dec ares an array of 5 ints, whereas the second dec ares an array of 10 String hand es
You m ght recogn ze th s second type from the main funct on that youve seen n a the examp es
Th s exerc se shows you how to create and terate over an array of ints
1. Create a new CLR Conso e App cat on project named IntArray
2. Add the fo ow ng code to main to create an array of ints and then fi
t w th some squares
Not ce how you access the array e ements by us ng the square-bracket notat on, w th the
ndex start ng at zero, just as n trad t ona arrays There s no reason why ndex ng must start
from zero, but t s trad t ona for anguages n the C fam y
3. Add another oop to pr nt out the va ues
for (int i=0; i<intArray->Length; i++)
Console::WriteLine("Element {0} is {1}", i, intArray[i]);
4. Bu d and run the app cat on, and ver fy that the va ues are pr nted
5. Mod fy the oop so that t tr es to read off the end of the array
for (int i=0; i<intArray->Length+1; i++)
Th s t me you shou d get an except on because the array object knows how many e ements t
has, and t wont et you try to access an e ement that doesnt ex st
Th s s an mportant d fference between trad t ona and managed arrays The managed array
s ho d ng a set of va ues for you, knows exact y how many t has, and snt go ng to et you
access an e ement that doesnt ex st
Initialization
You saw ear er how a trad t ona C++ array can be n t a zed by us ng an aggregate n t a zer You can
do the same w th managed arrays, so we can wr te the fo ow ng
array<int> ^intArray = gcnew array<int>(3) { 1, 2, 3 };
As you m ght expect, the comp er s c ever enough to work out the s ze of the array from the
n t a zer, so you can om t the d mens on, as demonstrated n the fo ow ng
array<int> ^intArray = gcnew array<int>() { 1, 2, 3 };
And, just ke trad t ona arrays, you can om t the ent re gcnew express on because the comp er
knows from the eft s de of the statement that you want an array<int>, as ustrated here
array<int> ^intArray = { 1, 2, 3 };
You can see th s by exam n ng the ma n funct on of any app cat on youve wr tten so far If you
ook at the defin t on of main, the first ne shou d ook ke th s
int main(array<System::String ^> ^args)
The args argument s a hand e to an array of String hand es, and you w
to see ng th s doub e caret pattern as you work w th managed arrays
The fo ow ng exerc se shows you how to create and use an array of reference types In th s examp e, you w use the System::String c ass, but you can eas y subst tute a reference type of your own
1. Create a new CLR Conso e App cat on named RefArray
2. Ed t the main funct on to match the fo ow ng
const size_t SIZE = 5;
int main(array<System::String ^> ^args)
{
Console::WriteLine("Arrays of Reference Types");
// Create an array of String references
array<String ^> ^arr = gcnew array<String ^>(SIZE);
// Explicitly assign a string to element zero
arr[0] = gcnew String("abc");
// Implicitly assign a string to element one
arr[1] = "def";
// Print the content
for (size_t i=0; i<SIZE; i++)
if (arr[i] == nullptr)
Console::WriteLine("null");
else
Console::WriteLine(arr[i]);
}
3. Comp e and run the app cat on, ensur ng that the va ues are pr nted as you expected
You shou d see two str ngs pr nted first, fo owed by three nu s Th s s because the array
object sets the String hand es to null when t s created, and you have on y ass gned to two of
them
You can a so use an aggregate n t a zer w th reference types, so you cou d have n t a zed the
array ke th s
array<String ^> ^arr = gcnew array<String^>(SIZE) {
gcnew String("abc"),
gcnew String("def") };
Each t me around the oop, an e ement from the array s ass gned to the String s, so that you can
use t w th n the body of the oop You do not have to know how b g the array s, and dont have to
n t a ze and ma nta n a counter Not hav ng to do th s means that there s ess chance to get an offby-one error n your code
There s another advantage to us ng the for each oop that m ght not be mmed ate y apparent
Th s oop doesnt on y work w th arrays; t works w th any co ect on that mp ements the IEnumerator
nterface Th s means that you can use the same programm ng construct to terate over very d fferent
k nds of co ect on
Enumerators
Enumerators are the NET mp ementat on of the Iterator des gn pattern, wh ch prov des an
abstract way to terate over any co ect on In NET, arrays and other co ect on types do th s by
mp ement ng the IEnumerator nterface, wh ch has the fo ow ng three members
The MoveNext method, wh ch moves to the next e ement n the co ect on, return ng false
when there are no more
The Current property, wh ch returns the tem current y be ng po nted to by the
enumerator
The Reset method, wh ch resets the po nter to just before the start
When you create an enumerator, t s pos t oned just before the first e ement Ca ng
MoveNext unt t returns false s guaranteed to v s t each e ement n the co ect on once,
a though w th some co ect ons, the order of traversa s not guaranteed
Us ng an enumerator means that you do not have to be concerned w th the under y ng co ect on type, mean ng (for nstance) that the mp ementat on cou d be changed to use a nked
st rather than an array, and the ca ng code wou d not have to change
Note, however, that you can on y read co ect ons through an enumerator If you want to
mod fy e ements wh e you traverse the co ect on, you w have to use a counted for oop
3. Bu d and run the app cat on to ensure that you see the same output
Multidimensional arrays
Just as n standard C++, you can create mu t d mens ona arrays n C++/CLI Un ke standard C++,
however, you dont prov de extra pa rs of square brackets, but nstead spec fy the d mens on ns de
the ang e brackets For examp e, here s how you wou d dec are a two-d mens ona array of ints
array<int,2> ^array2D = gcnew array<int,2>(3, 3);
Because you have two d mens ons, you need to spec fy two va ues n the constructor to set the
va ues for each d mens on
You a so obv ous y need to g ve two va ues when spec fy ng an e ement n a 2D array, but n C++/
CLI, you p ace both ns de a s ng e pa r of square brackets
array2d[1,1] = 7;
As you wou d expect, ndexes start from zero n a d mens ons, and you can genera ze the creat on and use of these arrays to any number of d mens ons you ke
You can use aggregate n t a zers w th mu t d mens ona arrays, and you use nested cur y brackets
to show wh ch va ues be ong to wh ch row of the array
array<int, 2>
{ 1, 2, 3
{ 4, 5, 6
{ 7, 8, 9
};
^array3d = {
},
},
}
Description
IsFixedSize
IsReadOnly
IsSynchronized
Length
LongLength
Rank
SyncRoot
Method
Description
AsReadOnly
BinarySearch
Clear
Clone
Copy
CopyTo
Exists
Find
FindAll
FindLast
ForEach
GetEnumerator
GetLength
GetLowerBound
When you run th s code, you shou d find that the rank s two and the tota ength s s x, wh ch
matches the dec arat on
4. The GetLength methodnot to be confused w th the Length propertyreturns the s ze of
any one d mens on of the array, so you can pr nt out the s zes of each d mens on, as presented
here
// Print out the array dimension information
for (i=0; i<arr->Rank; i++)
Console::WriteLine("Dimension {0} is of size {1}", i, arr->GetLength(i));
Now that you have an array and can find out how arge each d mens on s, you need to know
how to get and set e ements n the array
5. Add the fo ow ng nested oops to the end of your code
// Fill the array with values
for (j=0; j<arr->GetLength(0); j++)
for (k=0; k<arr->GetLength(1); k++)
arr[j,k] = (j+1)*(k+1);
The outer oop terates over the rows, whereas the nner oop terates over the co umns, and
the [x,y] notat on s used to reference the array e ements The Array c ass a so has the SetValue
method, wh ch prov des an a ternat ve way of sett ng va ues for those anguages that dont
support the array notat on sty e of C++
// Put '10' in array element [1,1]
arr->SetValue(10, 1, 1);
Aga n, the outer oop terates over the rows, and the nner oop terates over the co umns In
th s case, the GetLowerBound and GetUpperBound methods return the nd ces of the ower
and upper bounds The argument to GetUpperBound and GetLowerBound s the d mens on
of the array whose bound you want to find In C++, the ower bound s nvar ab y 0 and the
upper bound can be obta ned by us ng the GetLength method, so these are ma n y usefu n
other anguages for wh ch t m ght be common to have arrays w th arb trary ower and upper
bounds
7. Bu d and run the app cat on Check that the resu ts are what you expect
type as the or g na
// Create another multidimensional array of ints
array<int, 2> ^arr2 = gcnew array<int, 2>(3,2);
4. To copy some va ues over from the first array to the second, use the stat c Copy method
// Copy two values from arr to arr2
System::Array::Copy(arr,0, arr2,2, 2);
Us ng th s method, you can copy a or part of one array nto another The first two arguments
are the source array and the ndex from wh ch to start copy ng The second two are the dest nat on array and the start ng ndex at wh ch e ements are to be rep aced The fina argument
s the number of e ements to be cop ed In th s case, youve cop ed two e ements from arr nto
the m dd e of arr2, wh ch you be ab e to see f you add code to pr nt the contents of arr2,
such as n the fo ow ng examp e
for(j=arr2->GetLowerbound(0); j<=arr2->GetUpperBound(0); j++)
for(k=arr2->GetLowerbound(1); k<=arr2->GetUpperBound(1); k++)
Console::WriteLine("pn[{0},{1}] = {2}", j, k, arr2[j,k]);
Searching
Its common to want to search an array to see whether t conta ns a spec fic entry, and you can do so
by us ng the IndexOf and LastIndexOf methods
1. Create a new CLR Conso e App cat on project named Strings
2. Open the Str ngs cpp source fi e and add the fo ow ng code to the top of the main funct on to
3. The IndexOf and LastIndexOf funct ons both et you search to determ ne whether a part cu ar
object occurs n the array Add the fo ow ng code to the main funct on
// Search for a value
String ^s = "Dog";
int pos = Array::IndexOf(sa, s);
Console::WriteLine("Index of s in sa is {0}", pos);
// Search for the next occurrence
pos = Array::IndexOf(sa, s, pos+1);
Console::WriteLine("Next index of s in sa is {0}", pos);
The ca to IndexOf finds the first occurrence of the str ng Dog n the array and returns ts
ndex, wh ch n th s case s 0 The second ca , to an over oad of IndexOf, searches for an occurrence beg nn ng at a g ven offset Because the search s start ng just past the first occurrence,
the ndex returned s that of the second occurrence, wh ch s 4 A th rd over oad ets you
search w th n a port on of the array
Note If the value isnt found, the index returned will be one less than the lower
bound of the array, which in C++ will usually mean a value of 1.
LastIndexOf works n the same way as IndexOf, but t starts search ng from the other end of
the array
4. Bu d and run the app cat on
Sorting
The stat c Array::Sort method and ts over oads g ve you a way to sort an array or a part of an array,
whereas Array::Reverse ets you reverse the order of e ements Try add ng the fo ow ng code to the
main rout ne
Array::Sort(sa);
Array::Reverse(sa);
for each (String ^s in sa)
Console::WriteLine(s);
When you run the app cat on, you shou d see the e ements of the array pr nted n reverse order,
from Pig back to Cat
One va uab e over oad to Sort makes t poss b e for you to prov de two arrays, one of wh ch conta ns keys used to define the sort order Heres an exerc se to show you how th s works
1. Cont nue w th the project from the prev ous exerc se
Th s array conta ns the keys that youre go ng to use to sort the array of an ma names They
reflect my preferencescats are number one, wh e p gs come n at number s xso fee free
to change them as you ke
3. Add another ca to Sort, spec fy ng both arrays
Array::Sort(keys, sa);
Console::WriteLine("---Sorting with keys---");
for each(String ^s in sa)
{
Console::WriteLine(s);
}
The keys array s sorted, and the e ements n sa are sorted nto exact y the same order When you
run the code and pr nt out the array, the e ements w have been sorted from Cat to Pig
Using enumerators
You have a ready seen how you can use enumerators to terate over any co ect on, and that they are
what makes for each oops work w th co ect ons The GetEnumerator method on a co ect on returns
an enumerator that you can use to terate over the e ements of the co ect on
In th s next exerc se, you use an enumerator to st the e ements n the String array
1. Cont nue by us ng the Str ngs project; add the fo ow ng using dec arat on after the using
namespace System; ne
using namespace System::Collections;
You not ce severa th ngs about th s code To beg n w th, the enumerator starts off pos t oned before the first e ement, so you need to ca MoveNext once to get to the first e ement
When there are no more e ements to retr eve, ca s to MoveNext return fa se The property
Current retr eves the current object but doesnt move the po nter, so you get the same
va ue back unt you ca MoveNext aga n The Current property a so returns a genera Object
hand e, so you often need to cast th s to the actua type of the object by us ng the C++
dynamic cast or the NET equ va ent keyword, safe cast (See Chapter 11, Except on hand ng, for deta s on how to use safe cast )
What snt obv ous from the preced ng code s that the enumerator gets a snapshot of the
under y ng co ect on Enumerators are des gned for read-on y access to co ect ons, and you
can have severa ndependent enumerators act ve on the same co ect on at one t me If any
changes are made to the under y ng co ect on, the snapshot w fa out of synchron zat on,
wh ch causes the IEnumerator to throw an InvalidOperationException, a ert ng you that t no
onger reflects the under y ng data
Note Any type that wants to provide enumerator access to its members must implement
the IEnumerable interface. This interface has the one method, GetEnumerator, which returns
a pointer to some object that implements the IEnumerator interface.
Class
Description
Dictionary<K,V>
HashSet<T>
LinkedList<T>
A doub y nked st
List<T>
An expandab e array
Queue<T>
SortedList<K,V>
Stack<T>
Note The non-generic version of the List is System::Collections::ArrayList. This class was introduced before generics were added to .NET, and although it provides the same functionality, use of generic collections is preferred whenever possible because they are type-safe.
The fo ow ng exerc se shows you how to create a List and man pu ate t
1. Create a new CLR Conso e App cat on project named MyList
2. Open the MyL st cpp source fi e and add the fo ow ng ne mmed ate y after the using
namespace System; ne
using namespace System::Collections::Generic;
The defau t List constructor creates an empty List Because th s s a gener c type, you need to
spec fy the type that the List s to conta n, n th s case int
The next two nes use the Capacity and Count propert es to pr nt the current capac ty of the
List and a count of how many objects t current y conta ns If you run th s code, you find
that the count s 0not surpr s ng because you havent added anyth ng yetand that the
capac ty s a so 0 Us ng the fo ow ng a ternat ve constructor, you can spec fy a d fferent n t a
capac ty
// Create a List with a capacity of ten elements
List<int> ^pal = gcnew List<int>(10);
If you exceed the capac ty when add ng e ements, t w automat ca y be doub ed If your array s too arge, you can reduce ts capac ty to match the actua number of e ements stored by
ca ng TrimToSize You can a so reset the capac ty of the List at any t me by us ng ts Capacity
property
The List doesnt conta n any e ements unt you add some by us ng the Add or Insert funct ons
Add appends a new tem to the end of the st, whereas Insert takes a zero-based ndex and
nserts a new tem at that pos t on
4. Because List mp ements IEnumerator, you can pr nt out the contents of the List by us ng a
foreach oop
for each (int i in lst)
Console::WriteLine(i);
5. The syntax for remov ng tems from a List s s m ar to that used for retr ev ng them
// Remove item at index 2
lst->RemoveAt(2);
Console::WriteLine("---Item removed---");
for each(int i in lst)
{
Console::WriteLine(i);
}
If you want to remove more than one e ement, the RemoveRange funct on takes a start ng ndex and a number of e ements to remove In add t on, f you have stored a hand e to an object
n the co ect on, you can use the Remove funct on, wh ch w search the List and remove the
first occurrence
6. Bu d and run the app cat on
The IList nterface prov des the Add, Clear, Contains, IndexOf, Insert, Remove, and RemoveAt
methods, p us the Item, IsFixedSize, and IsReadOnly propert es
The ICollection nterface prov des the CopyTo method, p us the Count, IsSynchronized, and
SyncRoot propert es
You use these nterfaces to spec fy common funct ona ty for the co ect on c asses After you know
how the nterface methods work, t becomes eas er to use other co ect on c asses
The objects stored n the SortedList can mp ement the IComparable nterface w th ts
CompareTo method A the va ue types, such as number and str ng c asses, mp ement th s
nterface, and you shou d mp ement t on any other user-defined types whose va ues can be
ordered
An externa comparer object can be prov ded, wh ch mp ements the IComparer nterface w th
ts Compare method
The fo ow ng exerc se shows you how to create a SortedList and man pu ate t As an examp e,
suppose you wanted to ma nta n a st of emp oyees names together w th the r phone extens ons A
SortedList wou d work we n th s case, us ng the name as the key and the extens on as the va ue
1. Create a new CLR Conso e App cat on project named SortedList
2. Open the SortedL st cpp source fi e and add the fo ow ng ne mmed ate y after the using
namespace System; ne
using namespace System::Collections::Generic;
When you create a SortedList, you must spec fy the types for the key and the va ue w th n the
ang e brackets In th s case, we are us ng a String^ for the key, and an int for the va ue
As w th the List d scussed n the prev ous sect on, a SortedList has a defau t capac ty and w
automat ca y ncrease ts capac ty as necessary Us ng a ternat ve constructors, you can create
SortedList c asses w th part cu ar n t a capac t es, and you can tr m excess by us ng the Trim
ToSize funct on
The Add method takes key/va ue pa rs and adds them to the SortedList If the key a ready
ex sts n the co ect on, the method throws an ArgumentException
Note Keys cannot be nulls, but you can use nulls as values.
4. Add some code to pr nt out the contents of the SortedList by us ng a for each oop
for each (KeyValuePair<String^, int> kp in sl)
Console::WriteLine("Key={0}, value={1}", kp.Key, kp.Value);
Each e ement of the SortedList s returned as a KeyValuePair object, and you can use ts Key and
Value propert es to retr eve the key and va ue
1. In add t on to retr ev ng va ues by ndex, you can retr eve them by key, as demonstrated here
Console::WriteLine("Value for key 'Alice' is {0}", sl["Alice"]);
The ndexer uses the key to return ts assoc ated va ue f a match s found; f no match s found,
the ndexer throws an except on
As an a ternat ve to hand ng an except on, you can use TryGetValue, wh ch returns a bool to
et you know whether t found a va ue
int value = 0;
if (sl->TryGetValue("Fred", value))
Console::WriteLine("Value is {0}", value);
else
Console::WriteLine("Key not found");
In th s code, value s passed through to TryGetValue by reference so that the funct on can
update t
2. You can a so mod fy entr es n the st by us ng the ndexer, ke th s
// Change the value associated with key 'Alice'
sl["Alice"] = 5555;
Console::WriteLine("Value for 'Alice' is {0}", sl["Alice"]);
If the key a ready ex sts, ts assoc ated va ue s overwr tten; f t doesnt ex st, a new key/va ue
pa r s created
3. Bu d and run the app cat on
Note If you are new to C++ or have not encountered templates before, you might want to
skip this section on first reading.
A though gener cs and temp ates do have some features n common, they are very d fferent n the
way n wh ch they work, and ne ther of them can act comp ete y as a subst tute for the other For th s
reason, they are both supported n C++/CLI Because the use of temp ates n C++/CLI s an advanced
top c, th s sect on on y g ves a br ef summary of the s m ar t es and d fferences between the two
mechan sms
Temp ates are comp e-t me, gener cs are run-t me th s means that a gener c type s st
gener c at run t me, whereas a temp ate has been nstant ated at comp e t me
Temp ates support features such as spec a zat on, non-type temp ate parameters, and temp ate temp ate parameters Gener cs dont support these and are rather s mp er
Gener c types cannot nher t from a type parameter, as s the case w th temp ates
Gener c types support constra nts on type parameters, wh ch temp ates do not
Note If you want more details of the STL/CLR library, consult the reference documentation,
which, as of this writing, you can find at http://msdn.microsoft.com/en-us/library/bb385954.
aspx.
A vector s the equ va ent of an ArrayList a dynam ca y res zab e array The push back funct on
adds an e ement to the end of a sequence, and f you were us ng a nked st, you cou d a so use
push front to add va ues to the beg nn ng As you m ght expect, the pop back funct on removes an
e ement from the end Iterators are c asses, a ways ca ed iterator, that are defined w th n a conta ner,
so an terator to a vector<int> s a vector<int>::iterator You obta n an terator by ca ng the begin
funct on, wh ch returns an terator that po nts to the start of the sequence The end funct on returns
an terator po nt ng to the end of the sequence, and you use th s to check when you get to the end
You use terators ke po nters you can use ++ and to move them a ong the sequence, and * to
dereference them n order to get to the va ue at that pos t on The == and != operators are over oaded to compare pos t on f == for two terators returns true, they are po nt ng at the same pos t on
In case you th nk that th s does not sound very effic ent, the way that the STL has been wr tten,
mak ng heavy use of n ne code and temp ates, means that very effic ent code s generated at run
t me
Quick reference
To
Do this
CHAPTER 13
Properties
After comp et ng th s chapter, you w
be ab e to
ropert es have been ava ab e n some programm ng anguagessuch as M crosoft V sua Bas cfor
some t me, but the M crosoft NET Framework has added support for them nto M crosoft Intermed ate Language (MSIL) so that they can be eas y mp emented n any NET programm ng anguage
You see n th s chapter that propert es can often ead to a more natura sty e of programm ng w thout sacr fic ng robustness or v o at ng the pr nc p es of object-or ented programm ng
If users d rect y access data members, theyre requ red to know about the mp ementat on of
the c ass, and that m ght m t your ab ty to mod fy the mp ementat on ater
Users of your c asses m ght acc denta yor de berate ycorrupt the data n objects by us ng
nappropr ate va ues, poss b y ead ng to app cat on fa ures or other undes rab e resu ts
As a resu t, ts recommended that you h de data members, mak ng them pr vate and g v ng
nd rect access to them by us ng member funct ons In trad t ona C++, nd rect access has often been
mp emented by us ng get and set members Thus, a data member named date m ght be accessed
us ng a pa r of member funct ons named set date and get date Th s method works fine, but c ent
code a ways has to ca the get and set funct ons d rect y
229
Propert es n the NET Framework g ve you a way to mp ement a v rtua data member for a c ass
You mp ement the get and set parts of the property, and the comp er converts them nto ca s to the
get or set method as appropr ate
MyClass ^pmc = gcnew MyClass();
pmc->Name = "fred";
// calls the setter
s = pmc->Name;
// calls the getter
It appears to the user that MyClass has a rea data member ca ed Name, and the property can be
used n exact y the same way as a rea data member
Anyone who programmed n V sua Bas c wou d find the dea of mp ement ng propert es us ng
the get, set, and let methods fam ar In the NET Framework, propert es can be created and used
n any NET anguage, so you can create a c ass n V sua Bas c and st use ts propert es n a C++
app cat on, and v ce versa
Note If youve ever come across the overloaded [ ] operator in traditional C++, youll find
that indexed properties provide similar functionality, but you dont have to code the operator overload yourself.
Indexed propert es are a so mp emented by us ng getter and setter code, and the comp er automat ca y generates the requ red code so that c ents can use the square bracket notat on
The next sect ons n th s chapter demonstrate how to mp ement both sca ar and ndexed
propert es
Properties
2. Add the fo ow ng c ass defin t on after the using namespace System; ne and before the main
funct on
ref class Person
{
String ^name;
int age;
public:
// Person class constructor
Person()
{
Name = "";
Age = 0;
}
// The Name property
property String ^Name
{
String ^get() { return name; }
void set(String ^n) { name = n; }
}
// The Age property
property int Age
{
int get() { return age; }
void set(int val) { age = val; }
}
};
The c ass has two pr vate data members that ho d the name and age of the person Propert es
are ntroduced by the property keyword, wh ch s fo owed by a type and then the property
name It s convent on to beg n property names w th a cap ta etter
The getter and setter are dec ared ns de the property and ook a ot ke nested funct ons The
getter s a ways ca ed get and has a return type that matches the property type The setter s
ca ed set, takes an argument of property type, and has a return type of void
You can use the property from C++ code as f t were a rea data member of the c ass Note
how the propert es are used n the constructor n preference to us ng the data members
d rect y; you w see why th s s a good dea short y
Note The property names in this example are the same as the names of the underlying data members, but capitalized. It is a widespread convention in C# code that
function and property names are capitalized. Therefore, to fit into the .NET world, it
is a good idea if your property names are capitalized, as well.
3. Add the fo ow ng code to main to test the property
int main(array<String ^> ^args)
{
// Create a Person object
Person ^p = gcnew Person();
// Set the name and age using properties
p->Name = "fred";
p->Age = 77;
// Access the properties
Console::WriteLine("Age of {0} is {1}", p->Name, p->Age);
return 0;
}
After a Person object has been created and n t a zed, the name and age members can be
accessed through the Name and Age v rtua data members that have been generated by the
comp er
4. Bu d and run the app cat on
Errors in properties
What happens f a property get or set method encounters an error? Cons der the fo ow ng code
// Set the name and age using properties
p->Name = "spiro";
p->Age = -31;
How can the Age property commun cate that t snt happy w th a negat ve va ue? Th s s tuat on s
a good one n wh ch to use except ons, wh ch are d scussed n Chapter 11, Except on hand ng You
cou d mod fy the setter funct on to check ts argument ke th s
void set(int val)
{
if (val < 0)
throw gcnew ArgumentException("Negative ages aren't allowed");
age = val;
}
Auto-implemented properties
Many propert es s mp y ass gn to and return a data member, as shown n the fo ow ng
String ^name;
property String ^Name
{
String ^get { return name; }
void set(String ^n) { name = n; }
}
When that s the case, you can get the comp er to mp ement the getter and setter, and t w
generate a backing variable to store the data You dont see th s var ab e, but you access t nd rect y
through the property getter and setter
Th s means that you can mp ement the Name property very s mp y, as demonstrated here
property String ^Name;
In the next short exerc se, you can dec are and use an auto- mp emented property n your Person
c ass
1. Mod fy your Person c ass, prov d ng an automat c mp ementat on for the Name property and
Because you used the property n the constructor rather than ass gn ng to the data member,
chang ng to an auto- mp emented property st works
Whenever you use auto- mp emented propert es, you must use the property w th n your c ass
when ass gn ng to or read ng the va ue because you dont know the name of the back ng var ab e
that the comp er creates
exerc se
2. Type or ed t the defin t on of the Person c ass so that t ooks ke the fo ow ng code P ace t
after the using namespace System; ne and before the main method
ref class Person
{
int dd, mm, yyyy;
public:
// Person class constructor
Person(String ^n, int d, int m, int y)
{
Name = n;
dd = d; mm = m; yyyy = y;
}
// Auto implementation of the Name property
property String ^Name;
// The read-only Age property
property int Age
{
int get() {
DateTime now = DateTime::Now;
return now.Year - yyyy;
}
}
};
The c ass now has three nteger data members to ho d the date of b rth, n t a zed n the
constructor
The Age property now has on y a get method, wh ch retr eves a DateTime object represent ng
the current date and t me and then ca cu ates the age from the d fference between the current year and the stored year
3. Use the Name and Age propert es as you d d n the prev ous examp e
int main(array<String ^> ^args)
{
// Create a Person object
Person ^p = gcnew Person("fred", 4,9,1955);
// Access the Name and Age properties
Console::WriteLine("Age of {0} is {1}", p->Name, p->Age);
return 0;
}
You cant set the Age property because you havent prov ded a setter Th s w
p er error f you try to ass gn to the Age property
4. Bu d and run the app cat on
resu t n a com-
Th s c ass defines a property ca ed Area that s v rtua and wh ch can be overr dden by
subc asses
3. Add the defin t on for a Circle c ass, wh ch nher ts from Shape and wh ch a so mp ements
theArea property
public ref class Circle : Shape
{
double radius;
public:
Circle(double r)
{
radius = r;
}
virtual property double Area
{
double get() override {
return Math::PI * radius * radius;
}
}
};
The constructor for Circle takes a va ue for the rad us, wh ch s used n the Area property to
ca cu ate the area of the c rc e Note the p acement of the mod fiers on the Area property
dec arat on It s dec ared as virtual, and the get s dec ared as an override
4. Add a s mp e funct on to take a Shape and pr nt out ts area
void printArea(Shape ^s)
{
Console::WriteLine("Area is {0}", s->Area);
}
You w see that even though the printArea funct on has a Shape as ts argument type, t w
use the Circle mp ementat on of Area at run t me
An ndexed property makes t poss b e for you access the Account members by us ng array notat on, such as s demonstrated here
// Get a reference to one of the accounts held by the Bank
Account ^acc = theBank->Account[1234567];
You can mp ement get and set methods for ndexed propert es so that you can use them on both
s des of the equa s gn (=) The fo ow ng code fragment uses two propert es, w th the first ndexed
property g v ng access to an account, and the second g v ng access to an overdraft m t
// Set the overdraft limit for one of the accounts
theBank->Account[1234567]->OverDraft = 250.0;
2. Add a new C++ header fi e named Bank.h to the project When the fi e opens n the ed tor,
4. To ensure that everyth ng s correct, open the Banker cpp fi e and add code to the main func-
5. You must a so nc ude Bank h from the Banker cpp fi e so that the comp er w
know where to
ocate the dec arat on of the Bank c ass Therefore, add the fo ow ng code to Banker cpp after
the #include stdafx.h ne
#include "Bank.h"
6. Comp e and run the app cat on You shou d see the constructor message be ng pr nted on
the conso e
keth s
#pragma once
using namespace System;
ref class Account
{
public:
Account();
};
have an account number, a ba ance, and an overdraft m t, so add three pr vate members to the Account c ass defin t on n
Account h, as shown n the fo ow ng
private:
long accNumber;
double balance;
double limit;
4. Open Account cpp Ed t the constructor defin t on and mp ementat on as fo ows so that three
The bas c san ty check s mp y checks that the account number and overdraft m t arent negat ve If they are, t throws an ArgumentException
shown here
property long AccountNumber
{
long get() { return accNumber; }
}
You can add the funct on defin t on n ne n the c ass defin t on Remember to put t n the
pub c sect on
2. You a so need to add a read-on y property for the ba ance member, because n rea
fe, you
dont want peop e s mp y mod fy ng the ba ances n the r accounts from code
property double Balance
{
double get() { return balance; }
}
3. Add a read/wr te property for the overdraft m t because ts qu te poss b e that the m t
If you choose to mp ement these propert es n ne n the c ass defin t on, you need to add a
using namespace System; ne or fu y qua fy the name of ArgumentException before the code
w comp e
4. Test out your mp ementat on by add ng some code to the main funct on n Banker cpp to
create a new Account object and access ts propert es Inc ude the Account h fi e, and then add
code to create an Account object, as demonstrated here
// Create an Account object
Account ^theAccount = gcnew Account(123456, 0.0, 0.0);
The using dec arat on w make t eas er to use a List n the Bank c ass, and you need to reference the Account c ass ater
2. Add a List var ab e to the Bank c ass, ensur ng that ts pr vate
List<Account^> ^accounts;
Because List s a gener c co ect on, you need to spec fy what t s go ng to ho d In th s case,
the List s go ng to ho d Account hand es
3. Add the code for the pub c AddAccount method n ne n the header fi e as fo ows
bool AddAccount(Account ^acc)
{
// check if the account is already in the list
if (accounts->Contains(acc))
return false;
else
accounts->Add(acc);
return true;
}
AddAccount takes a hand e to an Account object and then uses the List::Contains method to
check whether the account a ready ex sts n the co ect on If t doesnt, the Account s added
to the co ect on
4. Add code for the RemoveAccount funct on, wh ch works n a very s m ar way
bool RemoveAccount(Account ^acc)
{
// check if the account is already in the list
if (accounts->Contains(acc))
{
accounts->Remove(acc);
return true;
}
else
return false;
}
Th s nforms the comp er that we are defin ng an ndexed property ca ed Balance that w use
a long as ts ndex type When you define the ndexed property, you nc ude the ndex as the first
parameter to the getter and setter
property double Balance[long]
{
double get(long idx) { ... }
void set(long idx, double value) { ... }
}
W th n the getter and setter, you can use the ndex to find the appropr ate va ue You can use the
ndexer ke th s
// Get the balance for account 12345
double bal = myBank->Balance[12345];
In th s exerc se you w mp ement an ndexed property to retr eve Account objects Because
you on y need to retr eve Account hand es and not set them, you mp ement a read-on y ndexed
property
1. Open the Bank h header fi e
2. Add the fo ow ng code to mp ement the property
// Indexed property to return an account
property Account ^default[long]
{
Account ^get(long num)
{
for each(Account ^acc in accounts)
{
if (acc->AccountNumber == num)
return acc;
}
throw gcnew ArgumentOutOfRangeException("No such account");
}
}
Default properties
You m ght wonder why the property s ca ed defau t It s poss b e for a c ass to have mu t p e
ndexers, but you have to use them exp c t y by name An ndexed property ca ed defau t, on
the other hand, can be used d rect y on an object, such as n the fo ow ng
// Get account 12345
Account ^acc = myBank[12345];
You norma y use the defau t ndexer for the property that s most often used
When you find an account whose number matches the one passed n, ts hand e s returned
If no such account s found, an except on s thrown because try ng to access a nonex stent
account s equ va ent to read ng off the end of an array It s a ser ous error that shou d be
s gna ed to the ca er
3. Test out the Bank c ass by add ng some code to the main funct on n Banker cpp You need
to start by ensur ng that the Bank h and Account h header fi es are nc uded Next add some
code so that your main funct on s s m ar to the fo ow ng
int main(array<String ^> ^args)
{
Console::WriteLine("Bank example");
// Create a bank
Bank ^theBank = gcnew Bank();
// Create some accounts
Account ^accountOne = gcnew Account(123456, 100.0, 0.0);
Account ^accountTwo = gcnew Account(234567, 1000.0, 100.0);
Account ^accountThree = gcnew Account(345678, 10000.0, 1000.0);
// Add them to the Bank
theBank->AddAccount(accountOne);
theBank->AddAccount(accountTwo);
theBank->AddAccount(accountThree);
// Use the indexed property to access an account
Account ^pa = theBank[234567];
Console::WriteLine("Account Number is {0}", pa->AccountNumber);
return 0;
}
After creat ng a Bank and a number of Account objects, you add the Account objects to the
Bank co ect on by ca ng Add You can then use the ndexed property to access an account
by number and use that po nter to d sp ay the ba ance Test the property by pass ng n an
account number that doesnt ex st and check that an except on s thrown
4. Bu d and run the app cat on and then check the output
Quick reference
To
Do This
mp ement a wr te on y property.
CHAPTER 14
be ab e to
e egates and events are extreme y powerfu and mportant constructs n the M crosoft NET
Framework Events n part cu ar are used w de y n GUI app cat ons as a means of commun cat ng
between components, but both de egates and events can be used to good effect n non-GUI code
245
The code dec ares a funct on po nter ca ed pf, wh ch can be used to nvoke any funct on
that takes two int parameters and returns a long The fo ow ng funct on prototype has the
r ght s gnature
long func1(int, int);
Remember that n C++, the name of a funct on w thout any parentheses eva uates to ts address, so the first ne takes the address of the funct on and stores t n pf The second ne uses
pf to nvoke the funct on
You can use a funct on po nter to nvoke any funct on that matches ts s gnature, and thats
what makes funct on po nters usefu for event hand ng You can define a funct on po nter to
represent the event hand er and then hook up the actua funct on to the po nter ater
d = 3.0;
result = Square(d);
= Cube(d);
= SquareRoot(d);
= TenToThePowerOf(d);
In each case, Im ca ng a funct on that has the same s gnature one that takes a double and returns
a double as ts resu t
W th de egates, I can define a mechan sm by wh ch I can ca any of those methods because they
a have the same s gnature Not on y can I ca any of the four methods above, but I can a so define
other methods and ca them through the de egateprov ded that they are a so funct ons that take a
double and return one Th s makes t poss b e for one c ass or component to define a de egate, and for
other c asses to attach funct ons to the de egate and use t You see examp es of th s use of de egates ater n the chapter when we cover events
In th s case, I want to use the de egate to ca one method at a t me, but ts poss b e to attach
more than one funct on to a de egate A the funct ons are ca ed n order when the de egate s
nvoked The NET Framework defines the System::Delegate c ass as the base for de egates that ca a
s ng e method, and System::MulticastDelegate as the base for de egates that can ca more than one
method A de egates n C++/CLI are mu t cast de egates
Defining delegates
Th s exerc se uses the numer ca operat ons examp e from the prev ous sect on to show you how to
create and use a s mp e de egate n C++/CLI code
1. Start M crosoft V sua Stud o 2012 and create a new CLR Conso e App cat on project named
Delegate
2. Open the De egate cpp source fi e and add the defin t on of a de egate to the top of the fi e,
The delegate keyword s used to define a de egate It m ght ook as though th s s a funct on
prototype for a funct on named NumericOp, but ts actua y defin ng a de egate type that
nher ts from System::MulticastDelegate Th s de egate type, named NumericOp, can be bound
to any funct on that takes one double as an argument and returns a double
Implementing delegates
Now that you have defined a de egate, you can wr te code to use t to ca funct ons One of the ru es
for us ng de egates s that you can on y use a de egate to ca funct ons that are members of C++/CLI
c asses; you cant use a de egate to ca a g oba funct on or a funct on thats a member of an unmanaged C++ c ass
be stat c members of a c ass, so add the fo ow ng c ass to your source code fi e, just above the
main funct on
ref class Ops
{
public:
static double Square(double d)
{
return d*d;
}
};
Th s managed c ass conta ns one pub c stat c method, wh ch s mp y takes a number and
returns ts square
2. Create a de egate n the main funct on of the app cat on, as shown here
// Declare a delegate
NumericOp ^op = gcnew NumericOp(&Ops::Square);
When you dec ared the de egate, you created a new type named NumericOp, so you can now
create a NumericOp object The constructor takes one argument th s s the address of the
funct on that s to be assoc ated w th the de egate, so you use the & operator to spec fy the
address of Ops::square
The object po nted to by op s now set up so that t w ca the square funct on when t s nvoked, and t w take exact y the same arguments (and return the same type) as Ops::square
Note You cant change the function that a delegate invokes after it has been created. This is one respect in which delegates differ from C++ function pointers.
3. Every de egate has an Invoke method that you can use to ca the funct on that has been
bound to the de egate Invoke w take the same arguments and return the same type as the
funct on be ng ca ed Add the fo ow ng nes to use op to ca the square funct on
// Call the function through the delegate
double result = op->Invoke(3.0);
Console::WriteLine("Result is {0}", result);
5. You can now eas y create another stat c member, create a de egate, and ca the funct on Test
th s out by add ng to the Ops c ass a second pub c stat c member ca ed Cube
static double Cube(double d)
{
return d*d*d;
}
6. Create another de egate n the same way as the first; however, th s t me, pass t the address of
There are two th ngs that you m ght not ce about th s code The first s that you have reused
the op reference to refer to the new de egate object Th s means that the or g na de egate
that you used to ca Square s no onger referenced; thus, s can be garbage-co ected
The second s that there s no exp c t ca to Invoke To m rror how de egates work n C# (and
how funct on po nters work n unmanaged C++), you can actua y om t the Invoke keyword,
treat ng the de egate as f t were a funct on ca tse f
7. Bu d and run the app cat on and check that t runs as you expect
The constructor spec fies the address of an object, myObject, and a member funct on be ongng tothe c ass to wh ch myObject be ongs Invok ng th s de egate s equ va ent to d rect y ca ng
myObject->MyFunction
Note All delegates that you create in C++/CLI by using the delegate keyword are multicast
delegates.
A de egate objects have an invocation list that ho ds the funct ons to be ca ed The nvocat on st
for a norma de egate has one member You can man pu ate the nvocat on sts for mu t cast de egates by us ng the Combine and Remove methods, a though th s s se dom done n pract ce
If you ook at the documentat on for the Combine method, you see that t takes two or more
Delegate objects as ts arguments You dont bu d up a mu t cast de egate by spec fy ng more
funct ons to add to ts nvocat on st Instead, a mu t cast de egate s bu t up by comb n ng other
de egates
The fo ow ng exerc se shows you how to create and use a mu t cast de egate
1. Create a new CLR Conso e App cat on project named Multicast
2. Open the Mu t cast cpp source fi e and add the defin t on of a de egate to the top of the fi e,
You can b nd th s de egate, named NotifyDelegate, to any funct on that takes one int as an
argument and doesnt return anyth ng
3. Youre go ng to ca two funct ons through the mu t cast de egate Because a funct ons ca ed
by de egates have to be members of a managed c ass, define two c asses at the start of your
project, each of wh ch conta ns a stat c member funct on
ref class Client1
{
public:
static void NotifyFunction1(int n)
{
Console::WriteLine("Client1: got value {0}", n);
}
};
ref class Client2
{
public:
static void NotifyFunction2(int n)
{
Console::WriteLine("Client2: got value {0}", n);
}
};
These two c asses are a most dent ca , both defin ng a s ng e stat c member funct on that has
the s gnature requ red by the de egate
4. You want to ca the two stat c member funct ons through one de egate, but you cant create
a de egate to b nd to two funct ons d rect y Instead, you need to create two norma de egates
(as you d d n the prev ous exerc se) and comb ne them nto a mu t cast de egate So, define
two de egates n the main funct on, each of wh ch b nds to one of the stat c methods
Console::WriteLine("Multicast Delegates");
// Create two delegates
NotifyDelegate ^del1 = gcnew NotifyDelegate(&Client1::NotifyFunction1);
NotifyDelegate ^del2 = gcnew NotifyDelegate(&Client2::NotifyFunction2);
At th s stage, you cou d nvoke both of the de egates, just as you d d n the prev ous exerc se
5. Bu d a mu t cast de egate from del1 and del2 by us ng the += operator, as shown n the
fo ow ng
// Create a third delegate from the first two
NotifyDelegate ^del3;
del3 += del1;
del3 += del2;
Remember that you dont have to ca Invoke exp c t y When you bu d and run the app cat on, you shou d see two nes of output, as shown n the fo ow ng screen shot
Note that the funct ons are ca ed n the order n wh ch the de egates are comb ned, so f you
want to change the order, you need to change the way you create the mu t cast
7. You can use th s de egate as the bas s for mak ng up another one
// Create a second multicast delegate and invoke it
NotifyDelegate ^del4 = del3 + del3;
Console::WriteLine("Invoking del4");
del4(5);
In th s case, youre comb n ng the nvocat on st of del3 tw ce, wh ch resu ts n the output
shown n the fo ow ng screen shot when you nvoke t Not ce how you can use the + operator to compose de egates at construct on t me
8. As the fina part of th s exerc se, you can use the = operator to remove an tem from a
de egates nvocat on st
// Remove an item
del3 -= del2;
Console::WriteLine("Invoking del3");
del3(5);
You spec fy the hand e of the de egate that you want to remove on the r ght s de of the =
operator If the de egate to be removed ex sts n the nvocat on st of the first de egate, t w
be removed In th s examp e, you have removed del2 from del3; when you nvoke del3, on y
del1 s executed
What happens f you create a mu t cast de egate that ca s severa such funct ons? Wh ch resu t w
be returned? It s most norma to use funct ons that dont return a va ue w th mu t cast de egates, but
252Microsoft Visual C++/CLI Step by Step
there s noth ng to stop you from ca ng funct ons that do return a va ue Usua y, the resu t of the ast
funct on executed w be returned, a though th s s mp ementat on dependent If you want to be sure
of retr ev ng a part cu ar va ue (or gett ng va ues from ntermed ate steps), you m ght want to wa k
over the st of de egates, wh ch you can do by us ng the GetInvocationList funct on w th n a for each
oop, as shown here
for each (MathOp ^m in myMultiDelegate->GetInvocationList())
{
double val = m();
}
by the source In th s examp e, two events w be used, so open the Event cpp source fi e and
define the fo ow ng two de egates mmed ate y after the using namespace System; ne
// Delegates
delegate void FirstEventHandler(String^);
delegate void SecondEventHandler(String^);
The de egates define the s gnatures of the methods that event rece vers must mp ement to
hand e the events, so theyre often g ven names that end w th Handler Each of these events
w s mp y pass a str ng as the event data, but you can make the data passed as comp ex as
you want
3. Add the mp ementat on of the event source c ass to the source fi e
// Event source class
ref class EvtSrc
{
public:
// Declare the events
event FirstEventHandler ^OnFirstEvent;
event SecondEventHandler ^OnSecondEvent;
// Event raising functions
void RaiseOne(String ^msg)
{
OnFirstEvent(msg);
}
void RaiseTwo(String ^msg)
{
OnSecondEvent(msg);
}
};
The first th ng to note s the use of the event keyword to dec are two events You need one
event dec arat on for each event that you want to ra se, and ts type s a hand e to the de egate
assoc ated w th the event So, n the case of the first event object, the type s FirstEventHandler
to match the FirstEventHandler de egate Us ng the event keyword causes the comp er to
generate a ot of de egate hand ng code for you; f youre nterested n exact y whats go ng
on, see the s debar that fo ows
You can then use the event objects n the EvtSrc c ass to ra se the events by us ng them as f
they were funct on ca s and pass ng the appropr ate argument
The raise method s protected so that t can on y be ca ed through the proper channe s
and not d rect y by c ent code
named EvtRcv
// Event receiver class
ref class EvtRcv
{
EvtSrc ^theSource;
public:
};
The rece ver has to know the event sources ts work ng w th to be ab e to subscr be and
unsubscr be, so we add an EvtSrc member to the c ass to represent the one source w th wh ch
you be work ng
2. Add a constructor to the c ass that takes a hand e to an EvtSrc object and checks that t snt
// Handler functions
void FirstEvent(String ^msg)
{
Console::WriteLine("EvtRcv: event one, message was {0}", msg);
}
void SecondEvent(String ^msg)
{
Console::WriteLine("EvtRcv: event two, message was {0}", msg);
}
FirstEvent s the hand er for the FirstEventHandler de egate, and SecondEvent s the hand er for
the SecondEventHandler de egate Each of them s mp y pr nts out the str ng thats been passed
to them
4. After you have the hand ers defined, you can subscr be to the event source Ed t the construc-
You subscr be to an event by us ng the += operator In the code, youre creat ng two new de egate objects, wh ch w ca back to the FirstEvent and SecondEvent hand ers on the current
object Th s s exact y the same syntax youd use f you were manua y creat ng a de egate The
d fference s n the += operator, wh ch comb nes the new y created de egate w th the event
sources de egate
As you read n the preced ng s debar, += ca s the comp er-generated add OnFirstEvent
method, wh ch n turn ca s Delegate::Combine
A though youve subscr bed to a the events automat ca y n the constructor, you cou d a so
use member funct ons to subscr be to nd v dua events as requ red
5. A match ng = operator ets you unsubscr be from events Add the fo ow ng member func-
t on to EvtRcv, wh ch w
// Remove a handler
void RemoveHandler()
{
// Remove the handler for the first event
theSource->OnFirstEvent -= gcnew FirstEventHandler(this,
&EvtRcv::FirstEvent);
}
The syntax for us ng the = operator to unsubscr be s exact y the same as that for the +=
operator to subscr be
6. Bu d the app cat on to ensure that there are no errors
The EvtSrc constructor takes no arguments, whereas the EvtRcv constructor must be passed
a va d EvtSrc po nter At th s po nt, the rece ver s set up, sten ng for events to be fired from
the source
int main(array<String^> ^args)
{
Console::WriteLine("Event Example");
// Create a source
EvtSrc ^src = gcnew EvtSrc();
// Create a receiver, and bind it to the source
EvtRcv ^rcv = gcnew EvtRcv(src);
// Fire events
Console::WriteLine("Fire both events:");
src->RaiseOne("Hello, mum!");
Ca s to the sources RaiseOne and RaiseTwo funct ons te t to fire both events When you run
th s code, you shou d see output s m ar to the fo ow ng screen shot
The rece ver has had both hand ers ca ed, so t has pr nted both of the messages assoc ated
w th the events
2. Insert some code to ca the RemoveHandler funct on of the rece ver and try fir ng both events
aga n
// Remove the handler for event one
rcv->RemoveHandler();
// Fire events again
Console::WriteLine("Fire both events:");
src->RaiseOne("Hello, mum!");
src->RaiseTwo("One big step");
Th s t me you shou d see on y the second message pr nted because the rece ver s no onger
hand ng the first event
Hand er funct ons do not have a return va ue and take two arguments The first s a reference to
the object that ra sed the event, and the second s a reference to an object of type EventArgs or a
subc ass Th s second argument s used to pass extra nformat on about the event For examp e, n
the case of a mouse-c ck event, t w conta n the pos t on of the cursor and deta s of wh ch mouse
button was c cked and whether any mod fier keys were used Because a system events fo ow th s
pattern, t s good pract ce to make your events and the r correspond ng de egates use th s mode ,
aswe
A the de egates used n the standard event mode w ook the same, hav ng the same two
arguments and void return type For th s reason, you dont need to keep defin ng your own de egate
types; nstead, you can make use of the System::EventHandler de egate, wh ch s des gned to ca funct ons that match the standard event hand er s gnature
The fo ow ng exerc se shows you how to use the System::EventHandler de egate You w define a
Counter c ass that conta ns a s ng e nteger va ue, wh ch you can ncrement by ca ng the increment
funct on When you construct a Counter, you can spec fy a m t, and an event w be fired when the
m t s reached
1. Create a new CLR Conso e App cat on named EventHandler
2. Add a new c ass ca ed Counter to the source fi e Th s c ass shou d have two data members
represent ng the current count and the m t, and they shou d be n t a zed n the constructor
ref class Counter
{
int count;
int limit;
public:
Counter(int lim)
{
count = 0;
limit = lim;
}
};
3. Add the dec arat on of a standard EventHandler event to the c ass, p ac ng t n the pub c
sect on
event EventHandler ^LimitReached;
4. Imp ement the Increment funct on, arrang ng for t to fire the LimitReached event at the ap-
propr ate po nt
void Increment()
{
Console::WriteLine("Count: {0}", ++count);
if (count == limit)
LimitReached(this, gcnew EventArgs());
}
Observe how the arguments to the event are a reference to the current object, and an
EventArgs object Th s defau t EventArgs object doesnt pass any extra nformat on to the
c entbut s necessary to conform to the de egate s gnature
to the source
ref class Observer
{
public:
static void CallMe(Object ^src, EventArgs ^args)
{
Console::WriteLine("Limit reached");
}
};
The stat c CallMe method has the r ght s gnature for an event hand er; thus, t can be bound
to the LimitReached event
6. Imp ement the main funct on Start by creat ng a Counter object w th an appropr ate m t set
and then b nd the CallMe method to the Counters LimitReached event F na y, ncrement the
Counter enough t mes that the m t s reached
int main(array<System::String ^> ^args)
{
// Define a counter with a limit of 3
Counter count(3);
count.LimitReached += gcnew EventHandler(&Observer::CallMe);
for (int i=0; i<5; i++)
count.Increment();
return 0;
}
When you bu d and run the app cat on, you shou d see the event hand er be ng ca ed when
the m t s reached, as shown n the fo ow ng screen shot
Quick reference
To
Do This
Define a de egate.
Create an event.
Ra se an event.
Subscr be to an event.
CHAPTER 15
be ab e to
Recogn ze the ma n namespaces that make up the NET Framework c ass brary
n prev ous chapters, you earned how to use C++/CLI to bu d s mp e app cat ons Now, ts t me to
move on to earn how to bu d rea M crosoft NET app cat ons that nvo ve GUIs, databases, web
servers, and a the other mechan sms needed by the modern M crosoft W ndows app cat on And
thats where the NET Framework comes n
The NET Framework s the brary of c asses that you use to bu d W ndows app cat ons It s arge,
comp ex, and far-reach ng n ts scope Th s chapter g ves you an overv ew of what the NET Framework s and what t can do before we cover some of ts features n more deta n ater chapters
App cat ons that use soph st cated GUI front ends
App cat ons that are d str buted over more than one computer
App cat ons that make use of databases and other data sources
There are two ma n components to the NET Framework the Common Language Runt me and the
NET Framework c ass brary You exam ne both components n th s chapter
263
Note If youre interested in seeing what IL looks like, you can use the IL Disassembler tool,
ILDASM, to open a .NET executable and show you the code in IL. Theres an example of how
to do so in the section Metadata later in the chapter.
Assemblies
Assemb es are the bas c bu d ng b ocks w th wh ch NET app cat ons are constructed, and theyre the
fundamenta un t of dep oyment and vers on ng Assemb es conta n IL code, metadata that descr bes
the assemb y and ts contents, and any other fi es needed for run-t me operat on An assemb y s
therefore much more se f-conta ned than a standard W ndows executab e or Component Object
Mode (COM) object because there s no re ance on externa sources of nformat on such as the W ndows Reg stry Every NET type s part of an assemb y, and no NET type can ex st outs de an assemb y
There are severa aspects by wh ch assemb es are fundamenta to the NET wor d
Versioning The assemb y s the sma est un t to wh ch vers on ng s app ed, and the assembly
manifest descr bes the assemb ys vers on together w th the vers ons of any assemb es on
wh ch t depends Th s nformat on means that ts poss b e to check that components w th the
wrong vers on nformat on arent be ng used at run t me
Deployment Assemb es are oaded on y as needed, wh ch makes them h gh y su tab e for
d str buted app cat ons
Type A types dent ty nc udes the assemb y n wh ch t res des Two types w th the same
name v ng n two d fferent assemb es are cons dered to be two comp ete y d fferent types
Security The boundary between assemb es s where secur ty perm ss ons are checked
Metadata
NET c asses are se f-descr b ng, wh ch means that they carry descr pt ve nformat on w th them n the
exe or d fi e Th s nformat on, ca ed metadata, nc udes the fo ow ng
The name, vers on, and cu ture-spec fic nformat on (such as the anguage and ca endar used)
for the assemb y
Informat on for each type n the assemb y name, v s b ty, base c ass, nterfaces mp emented,
and deta s of members
Add t ona attr bute nformat on
Most of the metadata s standard and s created by the comp er when t produces the IL code, but
you can use attr butes to add extra metadata nformat on
The fo ow ng exerc se shows you how to mod fy the standard metadata produced by the comp er
1. Start M crosoft V sua Stud o 2012 and create a new CLR Conso e App cat on project named
Meta1
2. Open So ut on Exp orer and ook at the Source F es fo der
You can see that the project conta ns three C++ source fi es Meta1 cpp s the code for the
app cat on, Assemb yInfo cpp conta ns defin t ons of the standard metadata tems that you
can mod fy, and StdAfx cpp s there to nc ude the StdAfx h header fi e
3. Open Assemb yInfo cpp
2012")];
Metadata s added to C++ code by enc os ng dec arat ons n square brackets ([]) Metadata s
most often attached to code to descr be c asses and funct ons Here, the keyword assembly: at
the start of the attr bute means that th s attr bute app es to an assemb y, as opposed to be ng
attached to code Theres a set of standard attr butes that you can use to change the metadata comp ed nto an assemb y, and most of them are sted n Assemb yInfo cpp
4. Ed t the AssemblyCompanyAttribute ne to conta n some su tab e name, such as the fo ow ng
[assembly:AssemblyCompanyAttribute("City Power & Light")];
5. Bu d the project, wh ch automat ca y creates the assemb y for you How can you be sure that
the metadata n the assemb y reflects your change? One way to find out s to use ILDASM,
wh ch s part of the NET SDK On my system, th s s ocated n the fo der \Program F es (x86)\
M crosoft SDKs\W ndows\v8 0A\b n\NETFX 4 0 Too s
Note I am using a prerelease version of Windows 8 and Visual Studio 2012, so the
location of ildasm.exe might be different on your system.
6. When the ILDASM w ndow opens, use the F e menu to nav gate to the Meta1 exe executab e
and open t You shou d see someth ng ke the screen shot that fo ows
A though the contents are presented n hexadec ma , you can see that the metadata does
reflect the change you made to the project
Youve a ready encountered NET namespaces n use n C++/CLI code when youve used the C++
using keyword, as n the fo ow ng examp e
using namespace System::Collections;
As w th trad t ona C++ namespaces, NET namespaces prov de an add t ona eve of scop ng that
he ps you to organ ze code and guard aga nst name c ashes Two c asses w th the same name can be
used n an app cat on, prov ded that they be ong to d fferent namespaces A type name that nc udes
the namespace nformat on s ca ed the fully qualified name, as ustrated n the fo ow ng examp es
System::Collections::Generic::List
System::Threading::Thread
Namespace names n NET typ ca y cons st of more than one word In C++/CLI, the components
of the name are separated by the scope reso ut on operator ( ) In many other NET anguages such
as C# and V sua Bas c, the components are separated by us ng a per od ( ), so n C#, the preced ng
examp es wou d be as fo ows
System.Collections.Generic.List
System.Threading.Thread
A c asses, nterfaces, structures, and enumerat ons that are part of the NET Framework c ass
brary be ong to a namespace Most of the namespaces prov ded by M crosoft beg n w th one of
two prefixes Those that start w th System have been deve oped as part of the NET Framework c ass
brary, whereas those beg nn ng w th Microsoft have been deve oped by other product groups w th n
M crosoft
Namespace names can have any number of components, but theres no h erarch ca re at onsh p
mp ed n names that conta n the same root components The h erarch ca nature of namespace
names s mp y g ves you a way to organ ze your c asses So, for examp e, System::Collections::Generic
and System::Collections both conta n co ect ons, yet they arent necessar y re ated n any other way
Note If you are a Java programmer, keep in mind that although .NET namespaces look
very much like Java package names, theres no relationship between namespace names and
directory paths as there is in Java.
Theres no requ rement that a the c asses be ong ng to one namespace are defined n the same
d fi e or that a s ng e d fi e conta ns c asses from on y one namespace
t oads the d fi e and reads the metadata for a the types that are defined there Because
mscor b d conta ns most of the core NET Framework c asses, t mports the metadata for a very
arge number of types
Note You can only use #using to reference assemblies defined in .dll files.
The #using keyword means that you have to know wh ch d fi e ho ds the c ass or c asses that you
want to use Your typ ca source for th s nformat on s the on ne he p
Some of the fu y qua fied names can get rather ong Thus, ts common to use a trad t ona using
d rect ve to spec fy namespace names so that you can use unqua fied names, as shown here
// Read the metadata for MSCORLIB
#using <mscorlib.dll>
// Import all the names
using namespace System::Collections::Generic;
// Now you can use List without having to qualify it
List<int> ^pal = gcnew List<int>();
Base c asses for common y used va ue and reference types, p us the base c ass for arrays
Attr butes
Except ons
Math
Floating-point types
The Single and Double types mp ement IEEE-754 float ng-po nt ar thmet c Th s means that every
operat on has a defined resu t, so you never get a d v de-by-zero error when perform ng float ngpo nt math; nstead, you get an answer of nfin ty The float ng-po nt c asses have va ues to represent
pos t ve and negat ve nfin ty and not a number (often represented as NaN), as we as methods to
test for them, as shown n the fo ow ng examp e
double top = 1.0;
double bottom = 0.0;
double result = top/bottom;
if (result == Double::PositiveInfinity)
Console::WriteLine("+infinity");
else if (result == Double::NegativeInfinity)
Console::WriteLine("-infinity");
else if (result == Double::NaN)
Console::WriteLine("Not a number");
As w th a the NET Framework c ass brary c asses, these c asses are anguage- ndependent
They can be used a ongs de or n p ace of the C++ stream c asses Chapter 19, Wr t ng a serv ce by
us ng W ndows Commun cat on Foundat on, de ves deeper nto some of the System::IO c asses The
System::IO c asses are n mscor b d
Note In earlier versions of the .NET Framework, you built UIs by using a technology called
Windows Forms, which was heavily influenced by Visual Basic.
One key feature of WPF s ts use of XAML, an XML markup anguage, to define user nterfaces
Th s makes t poss b e to separate the UI from the code, wh ch a ows teams to use des gn too s such
as M crosoft Express on B end n add t on to cod ng too s such as M crosoft V sua Stud o
System::Xml Prov des the bas c c asses needed for process ng XML
System::Xml::Linq Makes t poss b e to use Language-Integrated Query (LINQ) to work w th
XML data
System::Xml::Serialization G ves you the ab ty to ser a ze NET objects to and from XML
Us ng these c asses, ts poss b e to perform a the man pu at on of XML that you ever need to do
These c asses make the NET Framework one of the most product ve env ronments for XML programm ng You can find the XML c asses n System.Xml.dll, w th the LINQ c asses n System.Xml.Linq.dll
The most mportant c ass n the System::Data namespace tse f s DataSet, wh ch represents an
n-memory cache of data retr eved from a data source A DataSet cons sts of one or more DataTable
objects, and these n turn cons st of a co ect on of DataColumn and DataRow objects You can use
DataSets to work n disconnected mode Th s means retr eve data from a database nto a DataSet, d sconnect from the database server and work w th the data oca y, and then update the database from
the DataSet ater
System::Web Th s prov des the bas c funct ona ty for browser-to-server commun cat on over
HTTP, nc ud ng the HttpRequest and HttpResponse c asses that enab e an ASP NET page to
exchange data w th the c ent by us ng HTTP
System::Web::Mail Th s makes t poss b e for you to prepare and send ema attachments by
us ng the S mp e Ma Transfer Protoco (SMTP) serv ce that s bu t n to the W ndows operatng system
System::Web::Services Th s prov des the c asses w th wh ch you can bu d web serv ces
The features prov ded by two of these namespaces mer t part cu ar ment on A web service s a
programmab e ent ty v ng on a web server that can be accessed by us ng standard Internet protoco s What th s means n pract ce s that you can expose a funct on on a web server that others can
ca Commun cat on between c ent and server uses standard protoco s such as HTTP, and data s
usua y passed to and from the web serv ce n XML format by us ng S mp e Object Access Protoco
(SOAP) The use of XML over HTTP makes t poss b e to access web serv ces eas y from c ents wr tten
n just about any programm ng anguage on any p atform Its a so poss b e to find out what serv ces
a web server supports, and ts very easy n V sua Stud o 2012 to wr te c ents that make use of web
serv ces
W th the System::Web::UI namespaces, you can bu d server-s de contro s You program these as f
they were norma contro s, but the r code executes on the server The System::Web::UI::HtmlControls
namespace conta ns c asses that represent HTML server contro s that map d rect y to standard HTML
e ements such as buttons and forms System::Web::UI::WebControls s more abstract, and you can use
t to program server-s de contro s that m ght not map d rect y to HTML
Quick reference
To
Do this
Work w th XML.
PAR T I I I
Work ng w th fi es . . . . . . . . . . . . . . . . . . . . . . . . . . .
281
CHAPTER 17
305
CHAPTER 18
Us ng ADO NET . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
333
CHAPTER 19
Wr t ng a serv ce by us ng W ndows
Commun cat on Foundat on . . . . . . . . . . . . . . . . . .
351
CHAPTER 20
369
CHAPTER 21
397
279
CHAPTER 16
be ab e to
Understand how the M crosoft W ndows NET Framework performs nput/output (I/O)
Read and wr te fi es
ouve a ready used the Console c ass to perform I/O to and from the conso e Th s chapter ntroduces you to the System::IO namespace, wh ch conta ns the c asses, structures, and enumerat ons
that mp ement the M crosoft NET I/O mode
Note If you know anything about the Java I/O mechanism as implemented in the java.io
package, youll find it easy to start working with .NET I/O because the two have many
similarities.
281
Description
BinaryReader
BinaryWriter
BufferedStream
Directory
DirectoryInfo
File
FileInfo
FileStream
FileSystemInfo
FileSystemWatcher
IOException
MemoryStream
Path
Stream
StreamReader
StreamWriter
StringReader
StringWriter
TextReader
TextWriter
The I/O-or ented c asses n System::IO can be d v ded nto the fo ow ng three groups
The Stream c asses, wh ch are des gned for I/O of streams of bytes
The BinaryReader and BinaryWriter c asses, wh ch are used to nput and output NET pr m t ve
types, such as Int32 and Double, n b nary form
The TextReader and TextWriter c asses, wh ch are used for character-mode I/O
Using TextWriter
The TextWriter c ass has a number of usefu methods, as summar zed n the fo ow ng tab e
Method
Description
Close
Dispose
Flush
FlushAsync
Synchronized
Write
WriteAsync
WriteLine
WriteLineAsync
As you m ght guess from the nc us on of the Write and WriteLine funct ons n the tab e, the
Console c ass uses a TextWriter object to perform output
Asynchronous I/O
You m ght have not ced that the TextWriter c ass conta ns severa methods whose names end
w th Async Norma y, I/O operat ons prevent your code from execut ng further unt they fin sh,
a cond t on known as blocking Asynchronous I/O he ps overcome th s by perform ng I/O n the
background, ett ng your code cont nue execut ng wh e the nput or output operat on runs n
para e Th s s very usefu when you dont need to know that the operat on has fin shed, a though t s poss b e to find out when the operat on fin shes Sett ng up and work ng w th asynchronous I/O can be comp ex and s beyond what we can cover n th s ntroductory chapter
To show you how the I/O c asses work together, ets ook at how you use the StreamWriter c ass
Before we start, though, ts mportant that you understand how the NET Framework mp ements I/O
Rather than create a number of c asses that each perform an end-to-end I/O tasksuch as wr te a
str ng to a fi e or read a number from the keyboard NET mp ements a number of sma er spec a purpose c asses that you can p ug together to ach eve the effect you want Th s means that NET
doesnt have a wr te characters to a fi e c ass Instead, t has a wr te characters to a byte stream
c ass and a read bytes from a stream and wr te them to a fi e c ass If you p ug the output from the
first c ass nto the nput of the second, you end up wr t ng characters to a fi e
Th s mode s flex b e because you can take b nary or character data, convert t nto bytes, and then
pass the bytes to any of severa c asses to output them to fi es, memory, or a str ng Data s transferred
between the c asses as streams of bytes, a method that prov des a flex b e base on wh ch to bu d The
bas c funct ona ty for hand ng byte streams s prov ded by the Stream c ass, and you can bu d your
own spec a zed I/O c asses on top of Stream, f you need to
W th that nformat on n m nd, the exerc se that fo ows shows you how to wr te character data to
a text fi e by us ng a TextWriter Us ng the p ug-and-p ay mode for I/O that the NET Framework uses,
you need to create the fo ow ng two objects
CppWriter
2. The TextWriter and fi e I/O c asses are part of System::IO, so nc ude a using dec arat on at the
Note See the section The FileStream class later in this chapter for more details on
how to construct FileStream objects.
The code s enc osed n a try b ock because a ot of th ngs cou d go wrong when try ng to
open th s fi e
4. After you have n t a zed the FileStream object, create a StreamWriter that uses the FileStream,
as demonstrated here
try
{
// Create a FileStream
FileStream ^fs = gcnew FileStream("output.txt", FileMode::Create);
// Create a StreamWriter
StreamWriter ^sw = gcnew StreamWriter(fs);
}
catch(System::Exception ^pe)
{
Console::WriteLine(pe->ToString());
}
Note WriteLine performs buffered output, which means that it doesnt necessarily
write lines to the file every time you call the function. Instead, it maintains an internal buffer and writes the buffer to hard disk as necessary. One hard disk access per
buffer is more efficient than writing individual lines, but you need to call Flush at the
end of the code to ensure that output currently in the buffer is transferred to the
file.
A text fi e named output txt shou d appear n the CppWr ter project d rectory The fi e conta ns the three nes of text wr tten by the CppWr ter app cat on
3. Add code to main to ensure that the user has entered a fi e name
The argument to main s an array of the command- ne arguments, not nc ud ng the app cat on name
// Check for required argument
if (args->Length < 1)
{
Console::WriteLine("Usage: CppReader path");
return 0;
}
String ^path = args[0];
If the user hasnt g ven an argument, an error message s pr nted and the app cat on ex ts If
the user has prov ded t, the argument s saved for ater use
4. Its w se to check that the path represents an ex st ng fi e before cont nu ng, so add the fo ow-
ng code
if (!File::Exists(path))
{
Console::WriteLine("Invalid filename!");
return -1;
}
The File::Exists method checks whether a fi e w th the spec fied name ex sts, return ng fa se f
t doesnt It w a so return fa se f you g ve the name of a d rectory rather than a fi e Not ce
the return va ue of 1 Its a common convent on for C/C++ app cat ons to return 0 to nd cate
success, w th negat ve va ues be ng used to denote error cond t ons
5. Start st ng the fi e The first step s to create a FileStream and connect t to a StreamReader
try
{
FileStream ^fs = gcnew FileStream(path, System::IO::FileMode::Open);
StreamReader ^sr = gcnew StreamReader(fs);
}
catch(System::Exception ^pe)
{
Console::WriteLine(pe->Message);
}
throw an except on f
6. L st ng the fi e s done n th s oop, wh ch you shou d p ace after creat ng the StreamReader
object, ke th s
int count = 0;
for(;;)
{
String ^line = sr->ReadLine();
count++;
// If there are no more lines, break out of the loop
if (line == nullptr) break;
Console::WriteLine(line);
if (count % 20 == 0)
{
Console::Write("--more-- ");
String ^response = Console::ReadLine();
if (response->Equals("q")) break;
count = 0;
}
}
Console::WriteLine("-- end --");
The count var ab e s go ng to be used to count the nes as theyre read so that the app cat on knows where to break The oop reads a ne nto a String by us ng the ReadLine funct on
of StreamReader; f there are no more nes to read, a nu w be returned The ne s then
echoed to the conso e and the count checked Ive set the number of nes d sp ayed at one
t me to an arb trary va ue of 20; when the count s exact y d v s b e by 20, the app cat on
wr tes --more-- to the conso e and wa ts for the user to nput someth ng If the user presses
a owercase q, the app cat on stops; otherw se, t outputs the next set of nes
Remember that for(;;) sets up an nfin te oop, wh ch you need to term nate somehow In th s
examp e, when there are no more nes to read, the ca to ReadLine returns nullptr, and th s
causes the oop to term nate
7. Bu d and run the app cat on, g v ng the name of a su tab e text fi e as the argument
You can do th s n one of two ways The first s to open a command prompt, nav gate to the
d rectory conta n ng the executab e fi e, and then execute the app cat on from the command
ne just as you wou d w th any other app cat on
The second s to run the app cat on from w th n V sua Stud o, prov d ng the command- ne
arguments that you need In So ut on Exp orer, r ght-c ck the project name, and then, n the
shortcut menu that appears, c ck Propert es When the Propert es page appears, n the pane
on the eft, se ect Configurat on Propert es, c ck Debugg ng, and then enter the fi e name nto
the Command Arguments box n the center pane
Description
CreateDirectory
Creates a d rectory
Delete
EnumerateDirectories
EnumerateFiles
EnumerateFileSystemEntries
Exists
GetCreationTime
GetCurrentDirectory
GetDirectories
GetDirectoryRoot
GetFiles
GetFileSystemEntries
GetLastAccessTime
GetLastWriteTime
GetLogicalDrives
GetParent
Move
SetCreationTime
3. When the app cat on s run, the user can supp y opt ons n add t on to a fi e or d rectory path
Add the fo ow ng code to main to check that you have the m n mum number of opt ons
if (args->Length < 1)
{
Console::WriteLine("Usage: CppFiles [options] [path]");
return 0;
}
If the user has spec fied opt ons, we need to check what they are Each opt on s spec fied by a
s ng e etter, and mu t p e opt ons are spec fied as a str ng, for examp e, sa to choose the s
and a opt ons The opt ons supported by th s s mp e app cat on are s (for the fi e s ze), d
(for the ast mod fied date), and a (for the fi e attr butes) You can a so use v (for verbose)
as a shorthand to nd cate that you want them a It doesnt matter n what order the opt ons
etters are spec fied, or even f they are repeated
4. Add the fo ow ng code to main
String ^options = nullptr;
String ^path = nullptr;
bool hasOptions = false;
bool size = false;
bool date = false;
bool atts = false;
// If we have two arguments, we have options
if (args->Length == 2)
{
hasOptions = true;
options = args[0];
path = args[1];
// Parse the option string to set the option flags
ParseOptions(options, size, date, atts);
}
else
path = args[0];
5. Add the funct on that s go ng to process the opt ons, p ac ng t before main
The three bool var ab es are passed n by reference rather than by va ue; thus sett ng them n
th s funct on w change the r va ue back n the main funct on
6. Check whether the path represents a fi e or a d rectory by add ng the fo ow ng code to the
main funct on
bool isAFile = false;
bool isADirectory = false;
FileInfo ^fi = gcnew FileInfo(path);
DirectoryInfo ^di = gcnew DirectoryInfo(path);
if (fi->Exists)
isAFile = true;
else if (di->Exists)
isADirectory = true;
else
{
Console::WriteLine("No such file or directory");
return -1;
}
Th s snt qu te as stra ghtforward as you m ght th nk You have to create both FileInfo and
DirectoryInfo objects and then use the r Exists propert es to check whether e ther of them
recogn zes the path If ne ther of them returns true, the most ke y exp anat on s that the path
doesnt ex st, so you pr nt an error message and ex t
7. Now that you know what k nd of object you have and what opt ons the user wants, you can
pr nt out the deta s The first case s that for a s ng e fi e, and the code for that s very s mp e,
as ustrated here
if (isAFile)
{
ProcessFile(fi, size, date, atts);
}
8. Aga n, n the nterests of modu ar ty, p ace the code for process ng a fi e n a separate funct on
before main
void ProcessFile(FileInfo ^fi, bool size, bool date, bool atts)
{
// Echo the filename and length
Console::Write("{0,30}", fi->Name);
if (size) Console::Write(" {0,10}", fi->Length);
if (date) Console::Write(" {0}",
File::GetLastAccessTime(fi->ToString()));
if (atts)
{
FileAttributes fa = File::GetAttributes(fi->ToString());
Console::Write(" ");
if ((fa & FileAttributes::Normal) == FileAttributes::Normal)
Console::Write("<normal>");
else
{
if ((fa & FileAttributes::Archive) == FileAttributes::Archive)
Console::Write("a");
if ((fa & FileAttributes::Hidden) == FileAttributes::Hidden)
Console::Write("h");
if ((fa & FileAttributes::System) == FileAttributes::System)
Console::Write("s");
if ((fa & FileAttributes::ReadOnly) == FileAttributes::ReadOnly)
Console::Write("r");
}
Console::WriteLine();
}
}
The funct on first pr nts the fi e name and then d sp ays other deta s, depend ng on the opt ons chosen by the user The ast access t me can be obta ned by ca ng one of the stat c
methods on the File c ass, pass ng t the path The eas est way to get the path s to ca ToString
on the FileInfo object
Observe the use of a fie d w dth when pr nt ng the name; format spec fiers can take an opt ona fie d w dth after the fie d number If th s va ue s pos t ve, the va ue s r ght-just fied n
the fie d; f t s negat ve, the va ue s eft-just fied A fie d w dth of 30 characters shou d be
w de enough for most fi es
If the user has requested attr butes, use the stat c GetAttributes method on the File c ass to
obta n the FileAttributes You can then use the b tw se AND operator (&) to match aga nst
the var ous va ues defined n the FileAttributes c ass Th s code on y checks for four attr butes
There are many more, and t wou d be s mp e to extend the app cat on to check for them
9. If the user has entered a d rectory, st ts contents We w
else if (isADirectory)
{
// Process the subdirectories
array<String^> ^dirs = Directory::GetDirectories(di->ToString());
for (int i=0; i<dirs->Length; i++)
{
DirectoryInfo ^inf = gcnew DirectoryInfo(dirs[i]);
String ^name = inf->Name->ToUpper();
Console::Write("{0,30}", name);
Console::Write(" {0,10}", "--"); // no size for dirs
if (date) Console::WriteLine(" {0}",
Directory::GetLastAccessTime(inf->ToString()));
}
// Now do the files
}
The Directory::GetDirectories funct on returns an array of str ngs represent ng the names of
the subd rector es Loop over th s st, creat ng a DirectoryInfo object from each entry, and
pr nt ng out ts deta s Because there s no s ze for a d rectory, s mp y pr nt a coup e of dashes
10. Process the fi es by us ng the same funct on you defined ear er P ace the fo ow ng code after
tory You can then run the app cat on w th a su tab e command ne, such as the fo ow ng
CppFiles v ..
You shou d see output s m ar to the fo ow ng screen shot, st ng the fi es n the parent
d rectory
Tip If you want to run the application under the Visual Studio debugger, you will need to
provide the command-line arguments for the application. To do so, bring up the property
pages for the project. In the Configuration Properties section, click the Debugging option,
and then, in the Command Arguments edit control, enter the arguments. You can now run
the application in debug mode.
Binary I/O
B nary I/O n the NET Framework uses the BinaryReader and BinaryWriter c asses, wh ch read and
wr te NET pr m t ve types n b nary format As w th the TextReader and TextWriter c asses, the b nary
I/O c asses use an under y ng Stream object to prov de a byte stream Both BinaryReader and
BinaryWriter have a BaseStream property that g ves access to the under y ng Stream
Description
Close
Dispose
Flush
Seek
Write
Write7BitEncodedInt
If you ook at the V sua Stud o 2012 documentat on, you see that the Write funct on has no
fewer than 18 over oads for you to cope w th when wr t ng the var ous bas c types prov ded by
the NET Framework Because not a the types prov ded by NET are comp ant w th the Common
Language Spec ficat on (CLS), you need to be carefu when us ng some of the Write methods f you
ntend for the data to be read from code wr tten n other NET anguages
Note The CLS defines types that all .NET languages must support. The signed byte and
unsigned integer types are not included in the CLS, so they might not be usable from some
.NET languages. The most important of these is Microsoft Visual Basic .NET, which doesnt
support any of the nonCLS-compliant types.
public:
// Default constructor
Customer() : name(nullptr), accNo(0), balance(0.0) { }
Customer(String ^n, long ac, double bal)
: name(n), accNo(ac), balance(bal) { }
// Properties to retrieve instance data
property String ^Name
{
String ^get() { return name; }
}
property long AccountNumber
{
long get() { return accNo; }
}
property double Balance
{
double get() { return balance; }
}
// Write object
void Write(BinaryWriter ^bw)
{
bw->Write(name);
bw->Write(accNo);
bw->Write(balance);
}
// Read object
void Read(BinaryReader ^br)
{
name = br->ReadString();
accNo = br->ReadInt32();
balance = br->ReadDouble();
}
};
The c ass has three data members a String for the name, a long for the account number, and
a double for the ba ance There are constructors to create defau t and fu y popu ated objects,
and theres a set of read-on y propert es to a ow access to the data members
The Read and Write funct ons use BinaryReader and BinaryWriter objects to read and wr te the
state of the object n b nary format
4. Add the fo ow ng code to main to check that the user passes n a fi e name and save the path
as a String
if (args->Length == 0)
{
Console::WriteLine("Usage: CppBinRead [path]");
return 0;
}
String ^path = args[0];
Th s code s very s m ar to the argument-hand ng code that has been used n other exerc ses
n th s chapter Note that for s mp c ty Im not check ng the path for va d ty, but ts easy
and adv sab eto add such a check n a rea app cat on
5. Create some Customer objects
// Create some
Customer ^c1 =
Customer ^c2 =
Customer ^c3 =
customers
gcnew Customer("Fred Smith", 1234567, 100.0);
gcnew Customer("Jane Doe", 2345678, 1000.0);
gcnew Customer("Gill Evans", 3456789, 500.0);
6. To wr te the objects, you need a BinaryWriter and a FileStream to do the output to the fi e
FileStream ^fs = nullptr;
try
{
// Create a FileStream to write to the file
fs = gcnew FileStream(path, FileMode::Create, FileAccess::ReadWrite);
// Create a BinaryWriter
BinaryWriter ^bw = gcnew BinaryWriter(fs);
}
catch(IOException ^iex)
{
Console::WriteLine(iex->Message);
return -1;
}
finally
{
if (fs != nullptr) fs->Close();
}
Note You might find that Visual Studio complains that the FileMode and FileAccess
enumerations are ambiguous. You can ignore this because the code will compile
perfectly well.
7. Wr t ng the object data to the fi e s s mp y a case of ca ng the Write funct on, pass ng n a
po nter to the BinaryWriter Add the fo ow ng code at the end of the try b ock
// Write the objects to the file
c1->Write(bw);
c2->Write(bw);
c3->Write(bw);
8. Because the fi e was opened w th read/wr te access, you can now read from the fi e To do so,
create a BinaryReader object and attach t to the same FileStream, as shown here
// Create a BinaryReader that reads from the same FileStream
BinaryReader ^br = gcnew BinaryReader(fs);
9. Before you can read from a fi e to wh ch youve wr tten, you have to move the pos t on of the
seek po nter
// Move back to the beginning
br->BaseStream->Seek(0, SeekOrigin::Begin);
Not ce that th s code uses the BaseStream property and ts assoc ated seek po nter to get
at the under y ng Stream object If you havent encountered seek po nters before, read the
exp anat on n the fo ow ng s debar
10. Cont nue w th the project from the prev ous exerc se
11. Create a new empty Customer object and read ts deta s from the fi e, as fo ows
Customer ^c4 = gcnew Customer();
c4->Read(br);
Console::WriteLine("Balance for {0} (a/c {1}) is {2}",
c4->Name, c4->AccountNumber, c4->Balance);
The new Customer object has a ts fie ds set to defau t va ues The ca to Read d rects t to
read ts data from the current pos t on n the fi e
The obv ous potent a prob em s that the Read funct on w read from wherever the
BinaryReader s current y pos t oned If t snt at the beg nn ng of a Customer objects data,
you can expect to get an except on thrown
Tip If you want to save the state of objects in a real-world application, you wouldnt
do it manually like this. The System::Runtime::Serialization namespace contains classes that help you save and restore the state of objects in an efficient way.
12. Bu d and run the app cat on, prov d ng a su tab e fi e name
Quick reference
To
Do this
Wr te text to a fi e.
C HAP TE R 17
be ab e to
Wr te XML by us ng XmlTextWriter.
h s chapter ntroduces you to the XML capab t es of the M crosoft NET Framework XML p ays a
major ro e n NET as an enab ng techno ogy, and the NET Framework prov des fu support for
just about everyth ng you need to do w th XML
Note This chapter assumes that you already know something about XML. You should be
comfortable with elements, attributes, validation, namespaces, and all the other paraphernalia that make up XML.
There isnt ample space to give you a complete foundation in XML and the XML
technologies, so if you havent worked with it before, you might want to consult a book
such as XML Step by Step, Second Edition by Michael Young (Microsoft Press, 2002) before
reading further.
305
Note There are other, concrete reader classes in System::Xml, such as XmlTextReader
and XmlValidatingReader, and you might see these being used in older code. It is
now recommended that you use the XmlReader class, instead.
XmlTextWriter prov des a fast, forward-on y way to wr te XML to streams or fi es The XML
produced conforms to the W3C XML 1 0 spec ficat on, comp ete w th namespace support
XmlDocument mp ements the W3C Document Object Mode (DOM), prov d ng an n-memory
representat on of an XML document
Property
Description
AttributeCount
Depth
Encoding
EOF
HasAttributes
HasValue
IsEmptyElement
Item
LocalName
Name
NamespaceURI
If the nput conta ns ent t es or other features defined n a DTD, set DtdProcessing to Parse
If you want to va date the nput aga nst a DTD, set ValidationType to DTD and set
DtdProcessing to Parse
If you want to va date the nput aga nst one or more schemas, set ValidationType to Schema
and set Schemas to an XmlSchemaSet object that references the schema set
1. Start M crosoft V sua Stud o 2012 and create a new CLR Conso e App cat on project named
CppXmlReader
2. Add the fo ow ng ne to the top of CppXm Reader cpp
using namespace System::Xml;
Its eas er to use the c asses f you nc ude a using d rect ve for the System::Xml namespace
3. Add th s code to the beg nn ng of the main funct on to check the number of arguments and
4. Now that you have the path, create an XmlReader to parse the fi e We start w th a s mp e
parser, wh ch requ res a fu XML document rather than a fragment but doesnt do any
va dat on
try
{
// Create the settings object
XmlReaderSettings ^settings = gcnew XmlReaderSettings();
settings->ConformanceLevel = ConformanceLevel::Document;
// Create the reader...
XmlReader ^rdr = XmlReader::Create(path, settings);
}
catch (Exception ^ex)
{
Console::WriteLine(ex->Message);
}
The settings object s set to requ re a fu document and to gnore any comment nes Because
the XmlReader constructor takes the name of the document you want to parse, ts a good
dea to catch except ons here because severa th ngs can go wrong at th s stage, nc ud ng
pass ng the constructor a bad path name You can bu d and run the app cat on from the
command ne at th s stage f you want to check that the fi e opens correct y, or you can use
the Debugg ng page of the projects propert es to enter the fi e name and run t from w th n
V sua Stud o
Keep n m nd that XmlReader snt m ted to read ng from fi es You can over oad Create to
take XML nput from URLs, streams, str ngs, and other XmlReader objects
5. Pars ng the fi e s mp y means mak ng repeated ca s to the Read funct on unt the parser runs
out of XML to read The s mp est way to do th s s to put a ca to Read ns de a while oop Add
th s code to the end of the code ns de the try b ock
// Read nodes
while (rdr->Read())
{
// do something with the data
}
The Read funct on returns true or fa se depend ng on whether there are any more nodes to
read
6. Each ca to Read pos t ons the XmlReader on a new node, and you can then query the
NodeType property to determ ne the type of node w th wh ch you are dea ng Add the
fo ow ng code, wh ch dent fies severa of the most common node types
// Read nodes
while (rdr->Read())
{
switch (rdr->NodeType)
{
case XmlNodeType::XmlDeclaration:
Console::WriteLine("-> XML declaration");
break;
case XmlNodeType::Document:
Console::WriteLine("-> Document node");
break;
case XmlNodeType::Element:
Console::WriteLine("-> Element node, name={0}", rdr->Name);
break;
case XmlNodeType::EndElement:
Console::WriteLine("-> End element node, name={0}",
rdr->Name);
break;
case XmlNodeType::Text:
Console::WriteLine("-> Text node, value={0}", rdr->Value);
break;
case XmlNodeType::Comment:
Console::WriteLine("-> Comment node, name={0}, value={1}",
rdr->Name, rdr->Value);
break;
case XmlNodeType::Whitespace:
break;
default:
Console::WriteLine("** Unknown node type");
break;
}
}
Every t me a new node s read, the switch statement checks ts type aga nst members of the
XmlNodeType enumerat on I havent nc uded the cases for every poss b e node type, just
those that occur n the samp e document
Observe that the Name and Value propert es are used for some node types Whether a node
has a Name and a Value depends on the node type For examp e, e ements have names and
can have va ues, and comments have a va ue (the comment text) but not names Process ng
nstruct ons norma y have both names and va ues
A so not ce that nodes of type XmlNodeType::Whitespace are s mp y d scarded The vo canoes
xm fi e conta ns p enty of wh te space to make t readab e to humans, but the CppXm Reader
app cat on snt rea y nterested n wh te space, so the app cat on pr nts noth ng when t
encounters a wh te space node
7. Bu d the app cat on and run t from the command ne, g v ng the name of an XML fi e
CppXmlTextReader volcanoes.xml
XML declaration
Comment node, name=, value= Volcano data
Element node, name=geology
Element node, name=volcano
Element node, name=location
Text node, value=Ross Island, Antarctica
End element node, name=location
Element node, name=height
Element node, name=type
Text node, value=stratovolcano
End element node, name=type
Element node, name=eruption
Text node, value=constant activity
The first node s the XML dec arat on at the beg nn ng of the document, wh ch s fo owed by
a comment whose va ue s the comment text Each XML e ement n the document produces a
match ng pa r of Element and EndElement nodes, w th the content of a node represented by
anested Text node
You can see that the nodes are presented to you n near sequence, so f you want to keep
track of the h erarch ca structure of the document, youre go ng to have to put code n p ace
to do that
Handling attributes
XML e ements can nc ude attr butes, wh ch cons st of name/va ue pa rs and are a ways str ng data In
the samp e XML fi e, the volcano e ement has a name attr bute, and the height e ement has value and
unit attr butes To process the attr butes on an e ement, add code to the Element case n the switch
statement so that t ooks ke th s
case XmlNodeType::Element:
Console::WriteLine("-> Element node, name={0}", rdr->Name);
if (rdr->AttributeCount > 0)
{
Console::Write(" ");
while (rdr->MoveToNextAttribute())
Console::Write(" {0}={1}", rdr->Name, rdr->Value);
Console::WriteLine();
}
break;
The AttributeCount property nd cates how many attr butes an e ement has, and the MoveToNext
Attribute method makes t poss b e for you to terate over the co ect on of e ements, each of wh ch
has a name and a va ue A ternat ve y, you can use the MoveToAttribute funct on to pos t on the
reader on a part cu ar attr bute by spec fy ng e ther a name or a zero-based ndex
Attr butes are read a ong w th the e ement node of wh ch theyre a part When read ng attr butes,
you can use the MoveToElement method to pos t on the reader back to the parent e ement When you
run the code, you shou d see output s m ar to th s for nodes that have attr butes
-> Element node, name=height
value=13677 unit=ft
geology (volcano)+>
volcano (location,height,type,eruption+,magma,comment?)>
volcano name CDATA #IMPLIED>
location (#PCDATA)>
height EMPTY>
height value CDATA #IMPLIED
unit CDATA #IMPLIED>
type (#PCDATA)>
eruption (#PCDATA)>
magma (#PCDATA)>
comment (#PCDATA)>
Note Ive used a DTD for simplicity, but a schema can be used in exactly the same way.
If you check the samp e XML document aga nst the DTD, you not ce that theres a prob em The
e ement order ng for the second vo cano, Hek a, s ocat on-type-he ght rather than the ocat onhe ght-type order demanded by the DTD So, when you parse th s XML w th va dat on, youd expect a
va dat on error from the parser
1. Cont nue w th the project from the prev ous exerc se
2. Add a using dec arat on to the top of the CppXm Reader cpp, as shown here
using namespace System::Xml::Schema;
Some of the c asses and enumerat ons are part of the System::Xml::Schema namespace, and
the nc us on of the using dec arat on makes t eas er to refer to them n code
3. Add another property to the XmlReaderSettings to cause the reader to parse the DTD If you
settings->DtdProcessing = DtdProcessing::Parse;
4. If you a ready have a reader, you can add va dat on by cha n ng two readers together, as
demonstrated n the fo ow ng
// Create settings for DTD validation
XmlReaderSettings ^validationSettings = gcnew XmlReaderSettings();
validationSettings->ValidationType = ValidationType::DTD;
validationSettings->DtdProcessing = DtdProcessing::Parse;
// Create a validating reader and wrap the existing one
XmlReader ^validatingReader = XmlReader::Create(rdr, validationSettings);
The constructor for the second reader takes a reference to the n t a reader, wh ch t uses to
perform the bas c pars ng tasks Not ce how you must enab e DTD pars ng n the second sett ngs object as we as the first
5. Ed t a the code that parses the XML to use the new reader, validatingReader, rather than the
or g na reader, rdr
6. If you now bu d and run the app cat on, t shou d throw an except on when t finds the nva d
You can mprove on th s error hand ng by nsta ng an event hand er The parser fires a
ValidationEvent whenever t finds someth ng to report to you, and f you nsta a hand er for
th s event, you be ab e to hand e the va dat on errors yourse f and take appropr ate act on
7. Event hand er funct ons must be members of a managed c ass, so create a new c ass to host a
The ValHandler c ass conta ns one stat c member, wh ch s the hand er for a ValidationEvent
As usua , the hand er has two arguments a po nter to the object that fired the event, and an
argument object In th s case, the hand er s passed a ValidationEventArgs object that conta ns
deta s about the parser va dat on error Th s samp e code snt do ng anyth ng except pr ntng the error message, but n pract ce, youd dec de what act on to take based on the Severity
property of the ValidationEventArgs object
8. L nk up the hand er to the sett ngs object n the usua way
// Set the handler
validationSettings->ValidationEventHandler +=
gcnew ValidationEventHandler(&ValHandler::ValidationHandler);
Ensure that you set up the hand er before the ca to XmlReader::Create; otherw se, the reader
w not know about the va dat on
9. Bu d and run the app cat on Th s t me, you wont get the except on message, but you w
see
the messages pr nted out from the event hand er as t finds va dat on prob ems
10. Correct the order ng of the e ements n the XML fi e and then run the app cat on aga n You
Description
BaseStream
Formatting
Indentation
IndentChar
Namespaces
QuoteChar
Settings
WriteState
XmlLang
XmlSpace
The state of the wr ter nd cates what the wr ter s do ng at the po nt where you query the property It w report one of the va ues from the WriteState enumerat on, such as Start (no wr te methods
have been ca ed yet), Closed, Attribute ( t s wr t ng an attr bute), or Content ( t s wr t ng e ement
content)
Method
Description
Close
Flush
LookupPrefix
WriteAttributes
WriteAttributeString
WriteBase64, WriteBinHex
3. Add th s code to the start of the main funct on to check the number of arguments and save
the path
// Check for required arguments
if (args->Length == 0)
{
Console::WriteLine("Usage: CppXmlWriter [path]");
return -1;
}
String ^path = gcnew String(args[0]);
4. Create an XmlTextWriter by add ng the fo ow ng code (wh ch s very s m ar to the code used
The wr ter s created by spec fy ng the path for the new fi e and the character encod ng that
shou d be used Pass ng a nu po nter means that the wr ter w use the defau t UTF-8 encodng; th s s a good defau t cho ce
Note If you want to use another encoding, such as UTF-7 or ASCII, you can specify a
System::Text::Encoding object of the appropriate type.
5. Lets wr te the XML dec arat on to the fi e Add the fo ow ng nes to the end of the code
XmlTextWriter can produce output that emp oys ndents or that has no formatt ng The defau t
s no formatt ng, so you need to set the Formatting property f you want ndentat on The
defau ts for the ndentat on character (a space) and the ndentat on eve (two characters) are
usua y qu te acceptab e
320Microsoft Visual C++/CLI Step by Step
WriteStartDocument produces a standard XML dec arat on To ensure that a the text s output
to the fi e, you shou d ca Flush and Close before ex t ng
6. Wr te the root e ement to the document, as shown here
// Write the standard document start
writer->WriteStartDocument();
// Start the root element
writer->WriteStartElement("geology");
// Close the root element
writer->WriteEndElement();
CppXmlWriter test1.xml
You see that the app cat on wr tes an empty root e ement
<?xml version="1.0"?>
<geology />
8. To see how some of the other methods of XmlTextWriter are used, add one of the vo cano
ustrated n the fo ow ng
Ive eft n the root e ement code so that you can see how everyth ng nests Add ng extra e ements snt hard, but ts rather ong-w nded, and you have to be carefu to nest a the ca s
correct y
9. Bu d and run the app cat on, prov d ng t w th a su tab e fi e name The fi e shou d conta n
You can see how a the e ements conta n the r attr butes, how they are nested correct y, and
how everyth ng s proper y ndented
Using XmlDocument
Our hand ng of XML so far has been forward-on y, wh ch s very ght on resource usage but snt so
usefu f you need to move around w th n the XML document The XmlDocument c ass s based on the
W3C DOM, and ts the c ass that you want to use f you need to browse, mod fy, or create an XML
document
5. Add a constructor that creates an XmlDocument object, and nstruct t to oad the fi e that was
Un ke XmlReader, the XmlDocument c ass reads and parses the fi e when ts constructed
Note that youre not catch ng except ons here Someth ng m ght go wrong when open ng or
pars ng the fi e, but except ons are eft for the ca er to hand e
6. Add some code to the main funct on to create an XmlBuilder object Ensure that you are pre-
7. Try bu d ng and runn ng the app cat on at th s po nt F rst copy the vo canoes xm and
geo ogy dtd fi es you created ear er from the debug fo der nto the project fo der If you see
the Document oaded message d sp ayed when you run the app cat on, you know that the
document has been oaded and parsed
The next step s to access the nodes n the tree The current XML document conta ns three
vo cano e ements; what you do s find the second e ement and nsert a new e ement after
t There are a number of ways n wh ch you cou d do th s, but for now, I just ustrate one
method It snt the most effic ent way to do the job, but t does show how to use severa
XmlDocument and XmlNode methods and propert es
8. Cont nue work ng on the CppDom project Start work ng w th the tree by gett ng a hand e to
ts root Because you use th s root severa t mes, add an XmlNode^ member to the XmlBuilder
c ass, ke th s
private:
XmlNode ^root;
DocumentElement returns you the top of the DOM tree Note that th s s not the root e ement
of the XML document, wh ch s one eve down
10. You a so need to get the st of ch d nodes for the root Because you be us ng th s st aga n,
11. The code that fo ows shows how you can get a st of ch d nodes and terate over t Add th s
to the constructor
// get the child node list
nodelist = doc->ChildNodes;
IEnumerator ^ie = nodelist->GetEnumerator();
while (ie->MoveNext() == true)
Console::WriteLine("Child: {0}",
(dynamic_cast<XmlNode^>(ie->Current))->Name);
the fo ow ng code near the top of the CppDom cpp fi e, after the other using d rect ves
using namespace System::Collections;
13. If you run th s code on the vo canoes xm fi e, you shou d see output s m ar to the fo ow ng
Document loaded
Child: xml
Child: geology
Child: #comment
Child: geology
The root of the tree has four ch d nodes the XML dec arat on, the DOCTYPE dec arat on, a
comment, and the root node
Note After youve verified the existence of the child nodes, you can remove the
lines that declare and use the enumerator because you wont need them again. Be
certain that you dont remove the line that assigns the value to nodelist!
14. Now that you have the root of the tree, you need to find the root e ement of the XML by us-
The funct on creates an enumerator and terates over the ch dren of the root node The root
XML e ement w be of type XmlNodeType::Element and w have the name geology
15. After youve dent fied that e ement, the pub c funct on ProcessRoot s then used to process
The funct on s passed n the root node I know that the fi e Im work ng w th has more than
two vo cano e ements, and I know that I want to nsert a new one before the second e ement So, I can get a d rect reference to the second e ement by us ng the Item property on
ChildNodes to access a ch d node by ndex In rea code, youd obv ous y need to put n a ot
more check ng to ensure that you were retr ev ng the des red node
After the node has been retr eved, you ca CreateNewVolcano to create a new volcano e ement Then, you use InsertBefore to nsert the new one mmed ate y before the node you just
retr eved by ndex
16. Add the pub c CreateNewVolcano funct on, wh ch creates a new volcano e ement To save
space, I have om tted some the code for creat ng the ent re e ement; however, Ive nc uded
enough so that you can see how t works
XmlElement^ CreateNewVolcano()
{
// Create a new element
XmlElement ^newElement = doc->CreateElement("volcano");
// Set the name attribute
XmlAttribute ^att = doc->CreateAttribute("name");
att->Value = "Mount St.Helens";
newElement->Attributes->Append(att);
// Create the location element
XmlElement ^locElement = doc->CreateElement("location");
XmlText ^xtext = doc->CreateTextNode("Washington State, USA");
locElement->AppendChild(xtext);
newElement->AppendChild(locElement);
return newElement;
}
The funct on creates a new XmlElement for the vo cano Not ce that the node c asses
XmlElement, XmlComment, and so ondont have pub c constructors, so you need to create
them by ca ng the appropr ate factory method The name attr bute s appended to the
e ements co ect on of attr butes, and then the location e ement s created w th ts content
Bu d ng DOM trees ke th s s a process of creat ng new nodes and append ng them to one
another
17. It wou d be usefu to be ab e to pr nt out the mod fied tree, so add a pub c funct on named
Youve a ready seen the use of XmlTextWriter to create XML manua y You can a so use t to
output XML from a DOM tree by nk ng t up to an XmlDocument, as shown n the preced ng
code
18. Add ca s to ProcessChildNodes and PrintTree to the main funct on, and then bu d and test the
app cat on
try
{
XmlBuilder ^builder = new XmlBuilder(path);
builder->ProcessChildNodes();
builder->PrintTree();}
catch(Exception ^ex)
{
Console::WriteLine(ex->Message);
}
When you run the app cat on, you can see that the new node has been added to the tree
Remember that th s operat on has mod fied on y the DOM tree n memory; the or g na XML
fi e has not been changed
Quick reference
To
Do this
CHAPTER 18
Using ADO.NET
After comp et ng th s chapter, you w
be ab e to
Connect to a database
Create d sconnected app cat ons, wh ch use a DataSet to cache tab es n memory
DO NET s the data access API from M crosoft for the NET Framework ADO NET has been opt m zed to work w th NET, mak ng t poss b e for d str buted app cat ons and serv ces to exchange
data eas y and re ab y
ADO NET offers two d st nct programm ng mode s, depend ng on the type of app cat on you
need to bu d
If you requ re forward-on y, read-on y access to the data, you can use a DataReader to terate
over the resu ts of a query As you see, DataReaders are easy to use but requ re that you
rema n connected to the database as ong as you are us ng the reader
A ternat ve y, you can use a DataSet to represent an n-memory cache of data from the data
source You can create a DataSet, oad data nto t from the database, and then d sconnect
If you ed t the DataSet, you can a so update the database by us ng the changed data One
major advantage of the DataSet s that you on y need to be connected to the database wh e
exchang ng data; th s can make t a more sca ab e so ut on
In th s chapter, you w earn how to use ADO NET to connect to a data source, execute quer es,
and perform database update operat ons You w a so earn how to use a DataSet n a d sconnected
app cat on You w see how to fi a DataSet w th data from a database and d sp ay that data n a
gr d
333
Note ADO.NET provides access to any kind of relational database. To avoid the need to
download and install database engines and deal with complex setups, the examples in this
chapter use a Microsoft Access database. However, I want to emphasize that the principles
are exactly the same whether youre using Access or Microsoft SQL Server, and if you write
your code correctly, you should only have to change the configuration file to change to another database type.
What is ADO.NET?
ADO NET s a strateg c API from M crosoft for data access n the modern era of d str buted, Internetbased app cat ons ADO NET conta ns a set of nterfaces and c asses w th wh ch you can work w th
data from a w de range of databases, nc ud ng M crosoft SQL Server, Orac e, Sybase, Access, and
soon
Description
System.Data.SqlClient
System.Data.OleDb
System.Data.ODBC
System.Data.OracleClient
System.Data.EntityClient
System.Data.SqlServerCe
In add t on, data prov ders are ava ab e for a number of other databases through th rd-party
vendors Supported databases nc ude MySQL, IBM DB2, Inform x, Sybase, SQL te, F reb rd, and
PostgreSQL
ADO.NET assemblies
Many of the ADO NET c asses are n the System::Data assemb y, a though some of the newer features
(such as LINQ and Ent ty Framework) have the r own assemb es To use these assemb es, you need to
nc ude the appropr ate using statements n your app cat on, such as n the fo ow ng examp e
#using <System.Data.dll>
#using <System.Data.Entity.dll>
Note If you are creating projects by using Microsoft Visual Studio 2012, the reference to
System.Data.dll will be provided for you.
After you have mported the assemb es you requ re, you can add using d rect ves for the
namespaces, as shown n the fo ow ng examp e
using System::Data::SqlClient;
After you are connected, you w create a DbCommand object to represent a SQL statement You
then perform the fo ow ng tasks
Note You can find the sample database for this exercise, blog.mdb, in the sample code files
for this book. Before starting the exercise, copy this file to a directory on your hard disk.
Connecting to a database
In th s exerc se, you w create a new app cat on to perform a the operat ons descr bed n the preced ng sect on The first step s to connect to the database
1. Start M crosoft V sua Stud o 2012 and create a new CLR Conso e App cat on project named
ConnectedApplication
2. In the ConnectedApp cat on cpp fi e, after the using namespace System; statement, add the
fo ow ng statements
// Generic ADO.NET definitions
using namespace System::Data;
// Provider-independent classes
using namespace System::Data::Common;
3. Add an app cat on configurat on fi e to the project In So ut on Exp orer, r ght-c ck the project
name to open the Add New Item d a og box (v a the shortcut menu) In the pane on the eft,
c ck Ut ty, and then se ect Configurat on fi e (app config) as the fi e type Press Add, and a fi e
named app config w be added to the project and opened n the ed tor
When you next bu d your project you shou d see the message 1 fi e(s) cop ed d sp ayed n
the Output pane, toward the end of the bu d Note the doub e quotes around the dest nat on
They are needed f the path to the executab e conta ns spaces, and f that s the case and you
forget to put them n, the command w fa to execute
Remember to ed t the path to the ocat on where you stored the b og mdb database fi e
The connectionStrings sect on ho ds connect on str ng nformat on The clear e ement c ears
out the co ect on n case any have been nher ted from computer configurat on sett ngs In
th s examp e, we are defin ng a connect on str ng, dent fied by the name Blog, wh ch connects
to an Access database fi e by us ng the System.Data.OleDb prov der
338Microsoft Visual C++/CLI Step by Step
by fo ow ng the nstruct ons g ven n the s debar Referenc ng externa assemb es ear er n
the chapter
6. Add a using namespace d rect ve for System.Configuration
using namespace System::Configuration;
7. At the top of the main funct on, retr eve the connect on str ng sett ngs from the config fi e
ConnectionStringSettings ^settings = ConfigurationManager::ConnectionStrings["Blog"];
if (settings == nullptr)
{
Console::WriteLine("Couldn't get settings");
return -1;
}
Console::WriteLine("Have settings");
The ConfigurationManager c ass s respons b e for nteract ng w th sett ngs stored n configurat on fi es, and as such, t ma nta ns a co ect on of ConnectionStringSettings objects, wh ch
you can access by us ng an ndexer If the ca returns nu , there snt an entry w th that name
n the config fi e
8. After you have the ConnectionStringSettings object, you can use ts ProviderName property to
get a DbProviderFactory
// Get the factory object for this provider type
DbProviderFactory ^fac = DbProviderFactories::GetFactory(settings->ProviderName);
The DbProviderFactory s a factory that creates the var ous other objects that we need
connect ons, commands, and so on You use DbProviderFactory the same way, regard ess of
the actua prov der be ng used underneath
9. After you have the factory, use t to create a connect on and open t
DbConnection ^conn = nullptr;
try
{
// Create a connection and set its connection string
conn = fac->CreateConnection();
conn->ConnectionString = settings->ConnectionString;
conn->Open();
Console::WriteLine("Connection opened");}
catch (Exception ^ex)
{
Console::WriteLine(ex->Message);
}
finally
{
if (conn != nullptr) conn->Close();
Console::WriteLine("Connection closed");
}
Just about everyth ng you do w th databases can generate an except on, so you shou d a ways
enc ose your database code n a try b ock Connect ons need to be opened before they are
used, and t s mportant to c ose them afterward so that you free up resources The best way
to do th s s to use a finally b ock, wh ch ensures that the connect on s c osed whether or not
an except on occurs
10. Bu d your app cat on and fix any comp er errors
11. Run the app cat on
If a
s we , on the conso e, you see the message shown n the figure that fo ows
Th s statement returns an nteger nd cat ng how many rows are n the Entries tab e You w
ecute th s statement by us ng the ExecuteScalar method on the command object
ex-
Th s code creates and configures a DbCommand object that encapsu ates a SQL statement
The CommandText property defines the SQL to be executed, and CommandType says that
th s s a SQL command, as opposed to a stored procedure The Connection property spec fies
wh ch database connect on to use when execut ng the command
340Microsoft Visual C++/CLI Step by Step
3. Add the fo ow ng code to execute the SQL statement and d sp ay the resu ts on the conso e
// Print the result
int numberOfEntries = (int)cmd->ExecuteScalar();
Console::WriteLine("Number of entries: {0}", numberOfEntries);
Note Some fields in the SQL are surrounded with square brackets in case they have the
same name as predefined entities or types within Access.
You w use the ExecuteNonQuery method to execute th s statement, wh ch w return an nteger
to nd cate how many rows the statement affected Because you are nsert ng a s ng e row, youd
expect th s va ue to be 1
1. Cont nue w th the project from the prev ous exerc se
2. F nd the code you wrote n the prev ous exerc se and add the fo ow ng statement
// Update the prices of products
cmd->CommandText =
"INSERT INTO [Entries] ([Date], [Text], [Author])"
" VALUES ('Dec 02, 2012', 'A blog entry', 'Julian')";
Th s code reuses the DbCommand object from the prev ous exerc se but spec fies a d fferent
SQL statement
Tip It is a little-known feature of C++ that if the preprocessor sees two string literals
on adjoining lines, it will combine them. This is a useful way to split up and format
long strings.
3. Add the fo ow ng code to execute the SQL statement and d sp ay the resu ts on the conso e
int rowsAffected = cmd->ExecuteNonQuery();
Console::WriteLine("Added {0} rows", rowsAffected);
Th s code reuses the DbCommand object from the prev ous exerc se but spec fies a d fferent
SQL statement
3. Add the fo ow ng code to execute the SQL statement and return a DbDataReader object
DbDataReader ^reader = cmd->ExecuteReader();
4. Add the code that fo ows to oop through the resu ts one row at a t me For each row, output
the va ues of a four co umns The first, the record ID, s an nteger, but the other three (Date,
Text and Author) are a str ngs
Console::WriteLine("\n------------------------------------");
while (reader->Read())
{
Console::WriteLine("{0}: {1} by {2}", reader->GetInt32(0),
reader->GetString(1), reader->GetString(3));
Console::WriteLine(" {0}", reader->GetString(2));
}
Console::WriteLine("--------------------------------------");
The Read method steps through the record set one row at a t me Not ce the use of the
strong y typed methods GetString and GetInt32
5. After the oop, c ose the reader
reader->Close();
The message shown n the fo ow ng figure shou d appear on the conso e (You m ght get d fferent va ues than whats shown here )
A DataSet s an n-memory co ect on of DataTable objects and the re at onsh ps between them
You can create many DataTables n a DataSet to ho d the resu ts of more than one SQL query
Each DataTable has a co ect on of DataRows and DataColumns Each DataColumn conta ns
metadata about a co umn, such as ts name, data type, defau t va ue, and so on The DataRow objects
actua y conta n the data for the DataSet
You can create a DataSet from scratch, creat ng DataTables, sett ng up a schema us ng Data
Columns, and then add ng DataRows It s, however, much more common to use a DataSet w th a
database
The key to do ng th s s the data adapter, wh ch s ts between the database and the DataSet The
adapter knows how to retr eve data from the database and how to nsert and update data Each
prov der has ts own data adapter c ass, but as youd expect, you work w th the prov der- ndependent
DbDataAdapter type
Each data adapter works w th a s ng e DataTable n a DataSet You ca the Fill method on a
dataadapter to fi the DataSet w th data from the database You ca the Update method on a data
adapter to save any changes n the DataSet back to the database
Interna y, the data adapter has four command objects, one each for the se ect, de ete, nsert, and
update operat ons, each of wh ch encapsu ates a SQL command The fo ow ng tab e descr bes these
command objects
Command object in a data adapter
Description
SelectCommand
InsertCommand
UpdateCommand
DeleteCommand
og box, as deta ed n the s debar Referenc ng externa assemb es ear er n the chapter
3. Add using statements to the top of the source fi e for the assemb es that you are go ng to be
us ng
// ADO.NET namespaces
using namespace System::Data;
using namespace System::Data::Common;
// For reading the configuration data
using namespace System::Configuration;
// For printing the content of the DataSet
using namespace System::IO;
4. Add an app cat on configurat on fi e to the project In So ut on Exp orer, r ght-c ck the project
name On the shortcut menu that appears, po nt to Add, and then c ck New Item In the New
Item d a og box that opens, n the pane on the eft, c ck V sua C++, and then c ck Ut ty In
the center pane, c ck Configurat on fi e (app config)
5. Remember to add the post-bu d step to the project sett ngs so that app config w
be renamed to match the executab e name You can find deta s on how to do th s n the prev ous
exerc se
6. Copy the content of the app config fi e from the prev ous exerc se, Creat ng a connected ap-
Remember to ed t the path to reflect wherever you have stored the b og mdb fi e
7. Copy the code to read the connect on str ng sett ngs and create the DbProviderFactory (The
code s g ven here, but t s exact y the same as for the prev ous exerc se )
// Get the connection settings
ConnectionStringSettings ^settings =
ConfigurationManager::ConnectionStrings["Blog"];
if (settings == nullptr)
{
Console::WriteLine("Couldn't get settings");
return -1;
}
Console::WriteLine("Connection settings OK");
// Get the factory object for this provider type
DbProviderFactory ^fac = DbProviderFactories::GetFactory(settings->ProviderName);
8. Add a try b ock n wh ch you create a connect on, a catch b ock to hand e any errors, and a
finally b ock to c ose the connect on (Aga n, I have reproduced the code here, but you shou d
be ab e to copy t from the prev ous exerc se )
DbConnection ^conn = nullptr;
try
{
// Create a connection and set its connection string
conn = fac->CreateConnection();
conn->ConnectionString = settings->ConnectionString;
conn->Open();
Console::WriteLine("Connection opened");
}
catch (Exception ^ex)
{
Console::WriteLine(ex->Message);
}
finally
{
if (conn != nullptr)
{
conn->Close();
Console::WriteLine("Connection closed");
}
}
9. W th that setup comp ete, you can beg n retr ev ng data Start by ask ng the factory to create
a DataAdapter
// Create a DataAdapter and set its select command
DbDataAdapter ^adapter = fac->CreateDataAdapter();
10. A DataAdapter can have four commands assoc ated w th t, but because you are on y go ng
11. You can now create a DataSet and ask the adapter to fi
Note In a larger application, you could now close the connection to the database
because you have the data locally in the DataSet.
12. Now that you have a DataSet, t wou d be usefu to ook at what t conta ns The WriteXml
funct on wr tes the content of a DataSet n XML format to any stream The XmlTextWriter c ass
prov des a usefu stream for our purposes because t wr tes the output to a fi e n proper y
formatted form
XmlTextWriter ^xwriter = gcnew XmlTextWriter("c:\\SbS\\dataset.xml", nullptr);
xwriter->Formatting = Formatting::Indented;
The first two nes create an XmlTextWriter and ensure that t wr tes out the XML w th ndentat on Ed t the path to put the XML fi e n a su tab e ocat on Remember that you need to add a
using namespace statement for System::Xml, or use the fu name System::Xml::XmlTextWriter
Note The null second argument to the constructor means that the default UTF-8
encoding will be used. If you want to use another encoding, specify it like this:
XmlTextWriter ^xwriter = gcnew XmlTextWriter("c:\\SbS\\dataset.xml",
Encoding::Unicode);
The Encoding class is in the System::Text namespace, so you will need to add a using
declaration if you dont want to use the fully qualified name.
13. Use the tab es WriteXml method to wr te the data out to the fi e
DataTable ^table = dataset->Tables[0];
table->WriteXml(xwriter, XmlWriteMode::IgnoreSchema);
xwriter->Close();
The dec arat on of the DataTable hand e makes the fo ow ng code s mp er and shows how
the tab e created by the adapter s the first one n the DataSets Tables co ect on Because
you gave the tab e a name when the adapter created t, you cou d a so spec fy the name here
rather than the ord na The second argument to WriteXml shows that you on y want the data
and not the schema
14. Bu d and run the app cat on and then open the XML fi e n Notepad; you shou d see that the
The root e ement has the same name as the DataSet, and each row s named after the tab e If
you hadnt ass gned names to the DataSet and DataTable, the root e ement wou d have been
ca ed NewDataSet and each row wou d have been ca ed Tab e
15. Change the WriteXml statement so that t nc udes the schema n the generated data
table->WriteXml(xwriter, XmlWriteMode::WriteSchema);
Bu d and run the app cat on aga n; you shou d see that the output fi e conta ns an XML
schema that descr bes the data
<Blog>
<xs:schema id="Blog" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="Blog" msdata:IsDataSet="true"
msdata:MainDataTable="Entries" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded">
<xs:element name="Entries">
<xs:complexType>
<xs:sequence>
<xs:element name="ID" type="xs:int" minOccurs="0" />
<xs:element name="Date" type="xs:string" minOccurs="0" />
<xs:element name="Text" type="xs:string" minOccurs="0" />
<xs:element name="Author" type="xs:string" minOccurs="0" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
<Entries>
<ID>2</ID>
<Date>Jul 01, 2009</Date>
<Text>A first entry</Text>
<Author>Julian</Author>
</Entries>
...
Quick reference
To
Do this
Connect to a database.
Execute a command.
CHAPTER 19
be ab e to
More Info WCF is a very complex topic, and this chapter can only provide an introduction.
If you want to read more, I would suggest Windows Communication Foundation 4 Step by
Step by John Sharp, published by Microsoft Press.
We ve n an ncreas ng y connected and d str buted wor d When you v s t a webs te, your browser
connects across the Internet to a server, and that server n turn m ght be us ng other servers to prov de t w th resources
When you do th s, you have n effect created a d str buted app cat on Your browser prov des
the user nterface, the web server prov des the m dd e t er, and there can be other back-end servers
prov d ng the data t er One very mportant feature of systems ke th s s that you can connect comp ete y separate p eces together at run t me to get the funct ona ty that you want
351
These p eces m ght be wr tten by us ng d fferent anguages and frameworks, and run on d fferent
operat ng systems A that s mportant s the funct ona ty that they prov de, not the deta s of the r
mp ementat on
W th WCF, you can define contracts that spec fy, n a anguage and p atform- ndependent manner,
what serv ces your components can prov de, and these define the nterface of your component to the
outs de wor d The mp ementat on deta s are mmater a to the user
Distributed systems
Ear y frameworks for d str but on tended to be propr etary M crosofts D str buted Component Object
Mode (DCOM) was ntended to connect components wr tten by us ng M crosoft techno og es runn ng on W ndows Javas Remote Method Invocat on (RMI) was ntended to do the same th ng n the
Java wor d
A though these are st n use, the wor d has moved toward a need for more connect v ty and
ndependence, and so serv ce-based systems have become ncreas ng y popu ar
Services
One of the ha marks of modern serv ce-based systems s the ab ty to compose parts together that
have been deve oped ndependent y
Th s s done through the use of standards rather than propr etary techno og es So, for examp e,
we can use XML and HTTP to connect two components rather than RMI, wh ch was des gned to work
between Java components
You w see short y how WCF supports a w de range of the most popu ar and w de y used standards, mak ng t poss b e for you to create any type of serv ce that you m ght need
Characteristics of services
Serv ces have the fo ow ng d st ngu sh ng character st cs
Platform and language independence Serv ces are wr tten n such a way that they are not
dependent on c ents us ng a part cu ar anguage or framework to access them
Independent and autonomous Serv ces are ndependent n the same way that a webs te s
ndependent
Use well-known standards Serv ces make use of standard protoco s, such as TCP/IP and
HTTP, and data representat ons, such as XML Do ng th s decoup es c ents of the serv ce from
the mp ementat on
Discoverability Many serv ces pub sh metadata so that potent a c ents can d scover what
they offer and how to access them
Reusability Because serv ces are ndependent, when proper y des gned they can be comb ned nto new d str buted app cat ons
Connectivity
A component that you want to nteract w th cou d res de n another process on the same computer,
on another computer on your oca network, or out on the Internet You have severa opt ons for connect ng to such components
For components that res de on the same computer, you wou d use an nter-process commun cat on (IPC) mechan sm such as named pipes, whereas for components dep oyed on other computers,
you cou d use TCP/IP for b nary commun cat on or HTTP for text commun cat on In the enterpr se
wor d, t s a so common to use messag ng systems such as M crosoft MSMQ or IBM MQ to connect
components ocated on d fferent dev ces
The prob em here s that each of these commun cat on mechan sms s mp emented n a d fferent
way, us ng d fferent brar es and techn ques A deve oper exper enced n us ng TCP wou d have to
earn how to use messag ng
WCF s mp fies th s by ett ng deve opers nd cate how they want the r components to be connected and eav ng t up to the framework to mp ement the connect on For examp e, you can use an
attr bute to say that a c ass shou d be exposed as a web serv ce us ng HTTP, and WCF w generate a
the requ red code and configurat on
Endpoints
A serv ce n WCF s ca ed an endpoint Endpo nts are character zed by three facets
Contract
Contracts define what a serv ce can do, and contract deta s are expressed n metadata for c ents
touse
WCF supports four k nds of contracts
You use contracts dec arat ve y, by add ng attr butes to code Here s a s mp e examp e of a serv ce
contract
[ServiceContract]
interface class Foo
{
[OperationContract]
int SomeFunction(double d);
};
The nterface s annotated w th the ServiceContract attr bute, wh ch nforms WCF that you are
defin ng a set of operat ons Ind v dua funct ons w th n the nterface are marked w th Operation
Contract, wh ch makes them ava ab e to c ents Any funct on that snt marked w th OperationContract
w not be exposed to c ents
The operat on SomeFunction on y uses bu t- n types, and WCF knows how to marsha those Suppose, though, that you wanted to expose a funct on ke the fo ow ng as an operat on
Person^ GetPersonById(int id);
Note Marshaling is the process of converting data and sending it to another component.
This can involve converting it to an intermediate form for transmission over a network, and
it can result in the receiver getting a different representation than that of the sender.
In th s case, you wou d have to nstruct WCF how to marsha objects of type Person, and you cou d
do th s by us ng a DataContract
[DataContract]
ref class Person
{
[DataMember]
String ^name;
};
The DataContract c ass defines th s as be ng a ser a zab e c ass, and you app y DataMember to a
fie ds that you want to be ser a zed If you dont want or need to send a fie d, dont annotate t; th s
w cut down the amount of data be ng sent over the w re
Note As of .NET 3.5, you often dont have to annotate your types with DataContract and
DataMember, because public members will be made available by default. But it might be
wise to still use it, making explicit those members that you want passed to clients.
Request-response
One-way (a so ca ed simplex)
Dup ex (a so ca ed bi-directional)
Request-response s the defau t, and s typ ca y used when the c ent expects a rep y from the
serv ce For examp e, cons der th s operat on
Person^ GetPersonById(int id);
The c ent ca s the serv ce w th an ID and expects to get a Person back Us ng request-response
messag ng, the c ent w b ock (and the connect on w be ma nta ned) unt e ther the response has
been rece ved or a fau t has been sent Th s means that request-response message s synchronous, as
demonstrated n the fo ow ng ustrat on
How serv ce objects are created Is there just one or s there a new object created per ca ?
A deta ed descr pt on of behav ors and how to use them s beyond the scope of th s book
Creating a service
In th s exerc se, you w see how to create and test a s mp e serv ce that prov des mathemat ca operat ons To fo ow best pract ces, the serv ce w be defined as an nterface, w th the mp ementat on n a
separate c ass
1. Create a CLR Conso e App cat on project named MathService
2. Add an externa reference to System::ServiceModel and then add the fo ow ng two using
3. Add a header fi e named IMathService.h to the project, and use t to define the fo ow ng
nterface
#ifndef IMATHSERVICE_H
#define IMATHSERVICE_H
[ServiceContract]
public interface class IMathService
{
[OperationContract]
virtual double Square(double d);
[OperationContract]
virtual double Cube(double d);
};
#endif
Th s dec ares a serv ce as an nterface It s good pract ce to define serv ces us ng an nterface
because th s decoup es the mp ementat on from the defin t on Th s s be ng dec ared n a
separate header fi e because the c ent w need the nterface defin t on, as we
4. Open the MathServ ce cpp fi e and add the defin t on for a c ass that mp ements the serv ce
5. You can now start to mp ement the main method to host the serv ce
int main(array<System::String ^> ^args)
{
WSHttpBinding ^binding = gcnew WSHttpBinding();
Uri ^baseAddress = gcnew Uri("http://localhost:8080/MathService");
}
These first two nes create a b nd ng and a base address for the serv ce Because th s s a bas c
HTTP serv ce, you create a WSHttpBinding and an HTTP address
The ServiceHost s the object that mp ements the WCF behav or for you It s n t a zed w th
deta s of the serv ce mp ementat on c ass (so that t knows what to ca when requests
come n) and the base address You can then add an endpo nt to the ServiceHost so that t
knows to support the WSHttpBinding on the g ven base address and that t s support ng the
IMathService contract
7. Run the serv ce
host->Open();
Console::WriteLine("Service running... press Enter to terminate");
Console::ReadLine();
host->Close();
The ca to Open starts the serv ce sten ng for connect ons But th s s not a b ock ng ca , so
you need to keep the app cat on runn ng unt youre ready to c ose the connect on An easy
way to do th s s s mp y to output a prompt and wa t for the user to press Enter When the user
does press Enter, ensure that you c ose the host to free resources
8. Bu d the app cat on and run t to check that you have no errors
When you try to run the app cat on, you shou d find that t crashes w th an except on of
type System::ServiceModel::AddressAccessDeniedException Th s s because W ndows wants to
prevent poss b y ma c ous code runn ng w thout author zat on, so you need to run the app cat on w th suffic ent pr v ege There are two ways to do th s one s to reg ster the serv ce by
us ng the netsh command so that W ndows w a ow t to run; the other s to run the app cat on as an adm n strator, because adm n strators have r ghts to run serv ces To do that, you
can e ther start a command prompt as adm n strator and run the app cat on from the command ne or run V sua Stud o as adm n strator and run the app cat on from there
To run app cat ons as adm n strator n W ndows 8, r ght-c ck the app cat ons t e on the Start
screen and then, on the appbar menu that s des up from the bottom of the screen, c ck Run
As Adm n strator
2. In W ndows Exp orer, copy the IMathServ ce h fi e to the project d rectory and add t to the
ng the serv ce
4. Add the two using d rect ves for the System::ServiceModel and System::ServiceModel::Channels
namespaces
using namespace System::ServiceModel;
using namespace System::ServiceModel::Channels;
5. Add an #include statement for IMathServ ce h to the source fi e TestC ent cpp
6. Start mp ement ng the main funct on by creat ng a WSHttpBinding and EndPointAddress
WSHttpBinding ^binding = gcnew WSHttpBinding();
String ^url = "http://localhost:8080/MathService";
EndpointAddress ^address = gcnew EndpointAddress(url);
7. Commun cat on s hand ed by a Channel, and you get one of those from a ChannelFactory
ChannelFactory<IMathService^> ^factory =
gcnew ChannelFactory<IMathService^>(binding, address);
IMathService ^channel = factory->CreateChannel();
Note how the channe mp ements the nterface of the serv ce you want to ca , and a so has a
b nd ng and address It therefore has a the deta s t needs to contact the serv ce and use the
operat ons t prov des
8. Ca an operat on on the serv ce
double value = channel->Square(3.0);
Console::WriteLine("Value is {0}", value);
You need to cast the channe to an IChannel hand e because the IMathService doesnt mp ement the Close funct on
10. Bu d the app cat on to ensure that you have no errors
11. Run the MathService executab e that you created n the prev ous exerc se, wh ch you find
ocated n the Debug d rectory of the project When th s has started, run the c ent as adm n strator and you shou d see the resu t message pr nted out
More Info It isnt important for you to understand WSDL to create and use services, but
if you are interested, you can learn more about it at the w3schools website at http://www.
w3schools.com/wsdl/wsdl intro.asp.
The next quest on s how you ask a serv ce for ts metadata WCF serv ces expose the r metadata
through an MEX endpo nt When you add such an endpo nt, you can choose wh ch transports (HTTP,
TCP) that you want to support, and prov de the URL
You can use the WCF Test C ent to exam ne and ca serv ce operat ons, but your serv ce needs to
pub sh metadata through an MEX endpo nt before you can use th s
Th s next exerc se adds an MEX endpo nt to the serv ce It then shows how you can see the metadata and then use the WCF Test C ent to exerc se the serv ce
1. Cont nue w th the project from the prev ous exerc se
2. Add a using d rect ve for System::ServiceModel::Description to MathServ ce cpp
using namespace System::ServiceModel::Description;
3. Add the fo ow ng nes after the ca to AddServiceEndpoint and before the ca to Open
// Add MEX endpoint
ServiceMetadataBehavior ^mex = gcnew ServiceMetadataBehavior();
mex->HttpGetEnabled = true;
host->Description->Behaviors->Add(mex);
host->AddServiceEndpoint(
IMetadataExchange::typeid,
MetadataExchangeBindings::CreateMexHttpBinding(),
"http://localhost:8080/MathService/mex");
Ear er n the chapter, you earned that behav ors are used to mod fy the behav or of a serv ce
The ServiceMetadata behav or makes t poss b e for the serv ce to expose ts metadata v a
an MEX endpo nt, and you can configure how t exposes th s data In th s case, Ive chosen to
a ow c ents to access t v a an HTTP GET request The behav or object s added to the hosts
Behaviors co ect on, and then you add a serv ce endpo nt
The endpo nt exposes the IMetadataExchange contract at the URL by us ng HTTP at the g ven
address Note how the standard MEX endpo nt address s the serv ce address w th /mex
appended
By sett ng the HttpGetEnabled property, you can request the metadata us ng HTTP by pass ng
the wsdl parameter When the request executes, you shou d see the fo ow ng WSDL descr bng your serv ce n the browser
You can now run the WCF Test C ent, WcfTestC ent exe, wh ch you can find n C \Program
F es\M crosoft V sua Stud o 11\Common7\IDE (or f you are runn ng a 64-b t vers on of
W ndows, t w be n C \Program F es (x86)\M crosoft V sua Stud o 11 0\Common7\IDE)
6. When the app cat on starts, n the pane on the eft s de of the w ndow, r ght-c ck the
MyServ ce Projects entry, and then, on the shortcut menu that appears, c ck Add Serv ce
7. In the Add Serv ce d a og box that opens, enter the serv ce URL (http://localhost:8080/
8. Doub e-c ck one of the operat onsfor examp e, Square The pane on the r ght s de shows
you deta s of how to ca the operat on Enter a number n the Value fie d and press Invoke
After a short pause, you shou d see the response appear n the ower part of the pane, as
shown n the fo ow ng figure
1. Cont nue w th the project (MathServ ce) from the prev ous exerc se
2. Create a C# C ass L brary project named WcfClientLib
3. Add a reference to MathServ ce In So ut on Exp orer, under the project, r ght-c ck References,
dress box and press Go After a few seconds, you shou d see the MathService added to the
Serv ces pane You can expand th s entry and c ck on IMathService to see the operat ons n
the pane on the r ght
Observe the Namespace name at the ower eft, wh ch by defau t s ServiceReference1 the
generated code w be p aced n th s namespace You can change t f you want, but you
need to remember t for subsequent steps
5. When youre happy that you have a reference to the appropr ate serv ce, press OK and V sua
Stud o w
6. You dont need to add anyth ng e se to th s project, so just bu d t to create the DLL
b n debug d rectory
4. Add a using d rect ve for the namespace WcfClientLib.ServiceReference1.
using namespace WcfClientLib::ServiceReference1;
If you changed the namespace for the generated proxy code, ed t the using d rect ve
appropr ate y
5. The proxy c ass s dr ven by configurat on nformat on, so add an app cat on configurat on fi e
to the project R ght-c ck the project name, and then, on the shortcut menu, c ck to Add New
Item
6. In the d a og box that opens, n the Ut ty sect on, c ck Configurat on fi e (app config)
Note You need to edit the project properties so that the app.config file is properly
processed at build time. Open the project properties and then, under Configuration
Properties, click Post-Build Event, and specify the following command line:
copy app.config "$(TargetPath).config"
7. The configurat on deta s you need are n the DLLs app config fi e, so open that n the ed tor
The entr es n the configurat on fi e g ve a the deta s that the proxy needs to contact the
serv ce Ensure that you rep ace the va ue of userPrincipalName w th your deta s
8. You are now ready to use the serv ce Add the fo ow ng code to the main funct on
try
{
MathServiceClient ^msc = gcnew MathServiceClient();
double result = msc->Cube(3.0);
Console::WriteLine("Result: {0}", result);
}
catch(Exception ^ex)
{
Console::WriteLine(ex->Message);
}
The proxy c ass s ca ed MathServiceClient, based on the name of the serv ce w th C ent appended Th s c ass d rect y mp ements the operat ons exposed by the serv ce, so you can just
ca the Square and Cube funct ons w thout even hav ng to know that t s a serv ce
9. Ensure that the serv ce s st
runn ng and then bu d and run the c ent You shou d see the
resu t d sp ayed on the conso e
Quick reference
To
Do This
CHAPTER 20
be ab e to
he re ease of W ndows 8 has presented deve opers w th new opportun t es and cha enges, enab ng them to wr te app cat ons that make fu use of the capab t es of mob e dev ces, nc udng touch screens and cameras Th s chapter ntroduces you to the wor d of wr t ng W ndows Store
app cat ons for the new W ndows 8 env ronment
369
You can probab y guess what some of the parameters mean (x and y are the n t a pos t on of the
w ndow, and nWidth and nHeight spec fy ts s ze), but there are some obscure parameters and types
here
Creat ng app cat ons by us ng the W n32 API often means copy ng an ex st ng app cat on to get
a the bo erp ate startup and housekeep ng code, and then ed t ng the bus ness og c parts
Windows Forms
The first vers ons of NET ntroduced a new UI brary ca ed W ndows Forms (or WinForms), wh ch was
mode ed on the M crosoft V sua Bas c way of creat ng UIs, and (as the name mp es) t was targeted
at produc ng form-based app cat ons Because t was a NET brary, you cou d wr te W ndows Forms
app cat ons n any NET anguage
W ndows Forms app cat ons can have mu t p e w ndows, menus and too bars, d a ogs, and a the
other features that you wou d expect n a desktop W ndows app cat on
A W ndows Forms app cat on cons sts of one or more w ndows ca ed forms, and you typ ca y
deve op t by dragg ng contro s from a too box onto a form and then us ng the Propert es ed tor to
set contro propert es and event hand ers W ndows Forms was the first t me that C++ deve opers had
a v sua des gner for creat ng UIs
Note Although youd usually use the designer in Visual Studio to create Windows Forms
applications, Microsoft designed it so that you could create the entire UI in code if you
wanted to, and compile from the command line.
A form and ts ch d contro s are represented by objects n code, and the V sua Stud o des gner
creates the code that w generate the des red ayout at run t me Note that V sua Stud o 2012 does
not support W ndows Forms for C++/CLI It s poss b e that support m ght be added back n a ater
vers on, but for the t me be ng f you want to use W nForms, you w need to use V sua Stud o 2010
WPF uses D rectX rather than the o der GDI graph cs subsystem, wh ch makes for much faster
render ng and offers the ab ty to use hardware graph cs acce erat on when ava ab e
WPF uses XAML, an XML anguage, to descr be UI ayout Th s makes t poss b e to a most
comp ete y separate the presentat on and og c parts of an app cat on
WPF supports many advanced features that do not appear n W ndows Forms, nc ud ng r ch
support for med a (vector and raster mages, aud o, and v deo), an mat on, b tmap effects such
as drop shadows, and advanced text render ng
WPFs support for data-b nd ng s far more powerfu and extens b e compared to W ndows
Forms
WPF can have a steep earn ng curve because t s ntended as a profess ona graph cs brary w th
wh ch deve opers can create any UI they want rather than a brary that makes t easy to perform
common tasks and bu d s mp e bus ness app cat ons
Unfortunate y, WPF snt easy to use from C++/CLI, because the anguage acks support for part a
c asses, and th s feature s essent a f you are to work w th XAML Im not ent re y certa n why th s
wasnt added t wou d certa n y be poss b ebut t seems that M crosoft dec ded that t d dnt want
C++/CLI used for modern front-end deve opment Whatever the reason, there has never been a C++/
CLI des gner for WPF n V sua Stud o, and so there s no WPF App cat on project type
W ndows Store app cat ons are very d fferent to trad t ona W ndows app cat ons; they requ re
a d fferent approach to deve opment, as you w see n th s and Chapter 21, More about W ndows
Store apps
So, W ndows 8 supports two d fferent sty es of UI app cat on desktop and W ndows Store Note
that they are comp ete y separate Among other th ngs, th s means that a W ndows Store app wont
appear on the desktop and needs to run n the W nRT env ronment
The area on the eft, n green n the or g na d agram, s the new W nRT techno ogy stack, whereas
the area on the r ght (or g na y n b ue) shows ex st ng techno og es Th s does mean that deve op ng
for W ndows 8 now has two d st nct mode s, depend ng on the stack that you choose
You w not ce that NET s p aced n the o der, b ue sect on, but you w
to wr t ng W ndows Store apps
find that t s st
re evant
App behavior
Apps are secure and sandboxed, and cant wreck other app cat ons If users are go ng to down oad
apps from an on ne store, they need to be confident that a new one wont affect what they a ready
have nsta ed Down oad ng and nsta ng apps s made s mp er by us ng s ng e-fo der nsta at on
One consequence of sandbox ng s that some APIs are not ava ab e, such as sockets and fi e I/O
Apps oad qu ck y, w th none of the wa t ng common to desktop app cat ons In fact, you dont
start and stop apps ke you do the r cous ns on the desktop After you run an app t stays n memory
but s suspended f you sw tch away from t, so you can sw tch back to t nstant y Suspended apps
can be term nated f resources are needed; thus, apps need to hand e mov ng to and from the background and term nat on gracefu y
M crosoft s sett ng up a W ndows Store for W ndows 8 app cat ons, s m ar to the App Store
used on App e dev ces In common w th most of these stores, apps must be approved before be ng
accepted, and deve opers need to obta n a cense to be ab e to create apps You w see how to do
th s when you create your first app, ater n the chapter And f youre go ng to d str bute your apps
through the W ndows Store, they w a so need to be s gned w th a d g ta s gnature because anonymous app cat ons arent a owed
Hardware usage
The W nRT APIs make t poss b e for deve opers to take advantage of hardware features such as mot on sensors and cameras, and apps can adapt to the hardware context, such as sca ng to su t screen
reso ut on or us ng the mouse and keyboard when touch nput s not ava ab e
The UI model
The W nRT UI mode s ntended for use w th touch dev ces that have a m ted d sp ay area, so there
are some restr ct ons and un que aspects that you need to keep n m nd
Apps do not support over app ng w ndows An app can, however, have more than one w ndow, and you can move from w ndow to w ndow as you wou d n a browser
Cont nu ng the browser ana ogy, there are no menus or d a ogs
T es are used to represent programs on the desktop Un ke cons, t es are act ve and can d sp ay content (such as weather or a stock report) By do ng so, they can turn the desktop nto a
dashboard
Two types of UI are supported Code-based nterfaces can be wr tten n C#, C++, or V sua Bas c;
the UI s usua y constructed dec arat ve y by us ng XAML, a though t s poss b e to create the UI
manua y n code Web-based nterfaces are wr tten n JavaScr pt and constructed by us ng HTML5
and CSS3
Note When writing .NET applications, all languages are equivalent because they all compile down to Microsoft Intermediate Language (MSIL, or IL for short). In fact, you could say
that to a very large extent, the language that you choose reflects the syntax you prefer. This
is not the case when writing Windows Store apps, for which there are very real differences
in the three aforementioned approaches. There is some functionality available in JavaScript
that isnt available in C# or C++, and vice versa, but the main difference is that if you want
to use any Win32 and COM libraries you can only do it from C++. This means that to use
DirectX to write games, you will need to use C++.
The des gner oads (wh ch can take a few seconds), and you then see a screen w th a v sua
representat on of the UI n the upper ha f, and the XAML n the ower ha f The UI has a b ack
background because of the defau t theme that s used for app cat ons
The XAML s s mp y an XML document cons st ng of a Page e ement that represents the ent re
page, and wh ch conta ns a Grid e ement that w conta n the content for the page
Note You will learn about XAML in more detail later in the chapter. For now, lets
just note that a Page can only contain one content item, and this will usually be
some sort of layout control such as a Grid. As youd expect, a Grid can contain multiple items laid out in rows and columns.
5. On the eft s de of the V sua Stud o w ndow, c ck the Too box tab to d sp ay the Too box If
the tab snt v s b e, on the V ew menu, c ck Too box or press Ctr +W, X to d sp ay t
6. Drag a button from the Too box to the page
A button appears, wh e at the same t me a Button e ement s added to the XAML You can
drag the button around to pos t on t wherever you ke, and you can a so res ze t; the Buttons propert es n the XAML are updated to reflect any changes you make In fact, the upper
pane s s mp y a graph ca nterpretat on of the XAML, so converse y, f you ed t the XAML, the
upper pane w update tse f accord ng y
NoteThe Grid control can lay components out using rows and columns, but this
example is using absolute positioning. The Margin property determines how much
space is left on all four sides of a component, in the order left-top-right-bottom. By
specifying the first two, you are effectively defining the position of the button.
7. In the XAML pane, ed t the Buttons Content attr bute to someth ng more su tab e, such as
C ck Me!
Note You can provide the content to a control such as a button in two ways, either
by using the Content attribute or by providing it as the content of the element, such
as in the following example:
<Button Content="First One" ... />
<Button>Second One</Button>
In this example, which style you use is up to you, but if the content is going to be
something other than text (such as another XAML element), youll need to use the
second form.
8. Drag a TextBlock from the Too box to the page, pos t on t next to the button, and adjust ts
w ndow s v s b e by se ect ng Propert es W ndow from the V ew menu or typ ng Ctr +W, P
Now, se ect the TextBlock; you shou d see that the Name fie d at the top of the Propert es w ndow d sp ays <No Name> Enter a su tab e name such as TxtHello and press Enter The XAML
updates w th an x:Name attr bute, as shown n the fo ow ng figure
10. You now want the TextBlock to be updated when you press the button To do th s, you need to
add a hand er for the Buttons c ck event In the des gner pane, c ck the Button, and then, n
the Propert es w ndow, c ck the sma ghtn ng-bo t button at the upper r ght
Th s d sp ays a the events that the Button can ra se In th s case you just want to hand e the
c ck event, so doub e-c ck ns de the text box, next to C ck Th s adds a hand er w th a defau t
name to the Page c ass, wh ch ooks ke th s
void HelloXaml::MainPage::Button_Click_1(Platform::Object^ sender,
Windows::UI::Xaml::RoutedEventArgs^ e)
{
}
You earn more about event hand ng n Chapter 21, but you dont need much deta for
now, because you arent go ng to use e ther of the arguments
11. To change the text n the TextBlock, add th s ne of code to the hand er
TxtHello->Text = "Hello, XAML!";
The name that you gave the TextBlock s used as the name for the object that represents t n
code Any UI e ement that you want to nteract w th n code has to have a name; you d dnt
g ve a name to the Button because you arent nteract ng w th t n code, on y c ck ng t n the
UI at run t me
12. On the Bu d menu, c ck Bu d So ut on to bu d the app and ensure that you have no errors
W ndows Store apps run fu screen, so you see the ent re screen taken up w th your apps
UI, as dep cted n the screen shot that fo ows Press the button and check that the TextBlock
updates
Note Windows Store apps work differently than traditional Windows applications. Running
a Windows Store app doesnt just start it, it also adds it to the Start screen as an installed
application.
If youre new to W ndows 8 apps, you m ght be wonder ng how you get back to V sua Stud o after
youve performed test ng Mov ng the mouse to the ower- eft corner of the screen d sp ays the Start
con, wh ch you can use to get back to the Start screen When you get there, you not ce that your
app has been added to the st of ava ab e app cat ons on the r ght of the page, a though t doesnt
ook exc t ng because we havent defined any content for the t e yet
If you c ck the t e you be back at your apps UI, and you w probab y find that the TextBlock st
shows He o, XAML! Th s s because apps stay act ve after theyre started I say probab y because
apps can be term nated f there s pressure on resources, n wh ch case t wou d be restarted f you
c cked t aga n
If you dec de that you dont want the app to appear on the Start screen, r ght-c ck ts t e and then,
on the shortcut menu that appears, c ck Unp n From Start Even f an app cat on snt on the Start
screen, you can a ways execute t by us ng the A Apps charm on the command bar
Developer licenses
When you create a W ndows Store project, you m ght be prompted to obta n a deve oper
cense Th s s needed to create W ndows Store apps It ets you nsta and test apps on your
deve opment computer and then subm t them to the W ndows Store when youre ready to
show your code to the wor d You can find out more deta s on deve oper censes and how to
obta n them at http://msdn.microsoft.com/en-us/library/windows/apps/hh974578.aspx
Be aware that f you s gn n by us ng a M crosoft Account (former y M crosoft L ve ID), you
w be ssued a cense that needs to be renewed every 30 days If you create a W ndows Store
account, you can get a 90-day deve oper cense
XAML files App xam for the app cat on; Ma nPage xam for the defau t page Each page of
the app cat on has ts own XAML fi e, whereas App xam ho ds code and XAML that represents the app cat on tse f
Code-behind files A h and cpp fi e for each XAML fi e; for examp e, App xam h and App
xam cpp
The manifest file: Package.appxmanifest Th s conta ns metadata descr b ng the app cat on You can doub e-c ck th s to open t n the Man fest Des gner
The Assets folder Th s conta ns Portab e Network Graph cs (PNG) fi es conta n ng defau t
mages for the app cat on You can rep ace these w th your own mages to custom ze the appearance of your app cat on
Precompiled headers: pch.h and pch.cpp You can add your own headers to pch h,
whereas pch cpp s there s mp y to nc ude pch h
Note Precompiled headers are a feature of many C++ compilers. A lot of code is included
in header files, and in a typical application the same header files can be compiled for each
source file. Many of these header files will never change, and so precompiled headers let
the compiler process these once, and then reference the compiled version. Different compilers (and even different versions of Microsoft C++) use their own ways of handling precompiled headers, but for Windows Store apps any header files that are included in pch.h
will be precompiled.
There are a so a number of fi es that you shou dnt touch XAML app cat ons make heavy use of
part a c asses, and the g cpp and g h fi es represent the parts of c asses that are generated by V sua
Stud o
Introducing XAML
A though you can do a ot by just us ng the drag-and-drop funct ona ty n V sua Stud o and ett ng t
generate the XAML for you, understand ng how XAML works w make you a much more product ve
deve oper, and you a so find that there are some th ngs that you can on y do by ed t ng the XAML
yourse f In th s sect on, I ntroduce the concepts beh nd XAML and ts grammar
What is XAML?
XAML (Extens b e App cat on Markup Language) s used n W ndows RT and WPF to descr be user
nterfaces The dea beh nd XAML s that you create the user nterface dec arat ve y n XML, and the
comp er then generates the code to create the UI at run t me
Note Although XAML is mainly used for creating UIs, it provides a general way to describe
the relationships and properties of objects; thus, it is also used to describe workflows within
Windows Workflow Foundation.
There are three ways by wh ch you can create UIs
Create the UI comp ete y n XAML The markup anguage nc udes features such as data-b ndng and tr ggers, wh ch makes t poss b e for you to create soph st cated UIs w thout wr t ng
any code
Create the ayout n XAML, w th event hand ng code prov d ng the og c beh nd the UI Th s s
the most common y used approach, the defau t approach taken by V sua Stud o, and the one
that we use here
Create the UI comp ete y n code, w th no XAML Th s s not the recommended approach, but
t can be usefu for comp ex and dynam c UIs
XAML has a number of features that are espec a y usefu for construct ng UIs
Us ng XAML for declarative UI layout separates the UIs ook and fee Th s way, you can spec fy the
name of a buttons c ck event hand er w thout hav ng to know n wh ch anguage t s go ng to be
mp emented Th s a so makes t easy to separate the UI des gn and bus ness og c mp ementat on,
mak ng t poss b e for des gners to work on the XAML w thout hav ng to be concerned w th the code
XAMLs event hand ng ets you nk contro events to hand er funct ons n code, but you can a so
make event nks n XAML tse f For examp e, you can have a abe d sp ay the text of wh chever tem
you se ect n a st box or for the font s ze of a abe to be determ ned by the pos t on of a s der Th s
means that for many s mp e nteract ons between contro s, you dont need to wr te any code at a
Us ng Control templates, you can define ayout and v sua behav or temp ates that can then be
app ed to contro s across one or more app cat ons When comb ned w th CSS- ke styles and triggers
that can change sty es when events occur, you have a powerfu way to create un que and respons ve
UIs Temp ate and sty e deta s can be defined as resources n XAML, wh ch means that they can be
reused eas y If p aced n resource dictionaries, resources can be reused across projects
F na y, data-b nd ng s one of the most powerfu features of XAML, mak ng t poss b e for you to
b nd propert es on objects to data that can come from a var ety of sources I have a ready ment oned
one examp e, where the font s ze property of a contro can be bound to the pos t on of a s der You
can a so b nd to co ect ons of objects, so that a st box can d sp ay an array of tems, or you can b nd
to data retr eved from a data source
XAML syntax
In XAML, an object s represented by an XML e ement, and the objects propert es are defined by attr butes For examp e
<Button Content="Click!" Click="Button_Click"/>
Th s e ement represents a Button object It a so sets ts Content property and the name of the funct on used to hand e the c ck event It s easy to use custom c asses from XAML, prov ded the runt me
can ocate the assemb y conta n ng the object code
Re at onsh ps between objects are shown by nest ng e ements For examp e, a ListBox can have a
number of ListBoxItems, as demonstrated n the fo ow ng
<ListBox>
<ListBoxItem>Item 1</ListBoxItem>
<ListBoxItem>Item 2</ListBoxItem>
</ListBox>
If you want to nteract w th a contro from code, t must have a name, and you do th s us ng the
x:Name attr bute, as shown n th s examp e
<TextBlock x:Name="txtHello" ... />
The x: prefix nd cates that th s s the XAML Name attr bute, because a contro cou d have ts own
Name attr bute The prefix w be defined n one of the parent e ements of the TextBlock, as shown
here
<Page
...
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" />
<Grid ... >
<TextBlock x:Name="TxtHello" ... />
</Grid>
</Page>
In a W ndows RT app cat on, each page of a UI s represented by an object of a c ass der ved from
Page The defin t on of th s c ass s n a code-behind fi e, and the nk between the XAML and the c ass
s prov ded by the x:Class attr bute
<Page
x:Class="HelloXaml.MainPage" ... >
XAML a so makes use of markup extensions, wh ch are attr bute va ues enc osed n cur y brackets,
ke th s
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
Th s syntax nforms XAML that the attr bute va ue snt s mp y text; t s norma y used to create or
man pu ate objects
XAML controls
A XAML UI s made up of contro s Everyth ng s a contro , from the top- eve w ndow to the mage
d sp ayed on a button Heres an mportant pr nc p e XAML UIs are constructed by nest ng contro s
w th n one another, and there s on y one contro at the top eve , wh ch w be a conta ner such as a
Window or Page
We can d v de contro s nto two broad types content controls (wh ch can on y conta n one tem)
and items controls (wh ch can conta n more than one)
Note There are a number of commonly used controls that dont belong to these two
groups (such as the Calendar and DatePicker) but for the purposes of explaining XAML, for
the moment, Ill keep it simple.
A content contro can on y conta n one other tem as ts content; for nstance, a Button can d sp ay
a p ece of text or an mage, but th s can be an tems contro As an examp e, a Button can conta n a
StackPanel wh ch ho ds both an mage and some text, as shown n the fo ow ng ustrat on
The StackPanel st fi s a the ava ab e space, but th s t me, t ays out ts ch dren hor zonta y By
defau t, the ch d contro s are centered vert ca y
If you have so many tems n a StackPanel that they arent a v s b e at one t me, you wont see the
contro s that fa outs de the bounds of the StackPanel, but a of the objects w st be created The
VirtualizingStackPanel manages th s effic ent y by on y creat ng ch d contro s when theyre v s b e
The Grid s one of the most common y used ayouts Items are arranged by row and co umn, and
ce s can have d fferent s zes You can spec fy the number of rows and co umns as we as wh ch ce
a ch d contro shou d occupy The ustrat on that fo ows d sp ays how three buttons ook when
d sp ayed n a Grid
You can see how RowDefinition and ColumnDefinition e ements are used to define the rows and
co umns n the gr d There are severa ways to define the w dth and he ght, such as by us ng percentages or abso ute va ues In th s case, the aster sk (*) denotes a proport on, so the w dths of the two
co umns are d str buted proport ona y n the rat o 60 40 L ke the StackPanel, there s no s ze spec fied
for the Grid tse f, so t fi s a the ava ab e space The other mportant concept shown by th s examp e
s the way n wh ch the row and co umn va ues are spec fied for the buttons Th s s done by us ng attached properties, wh ch are exp a ned n more deta n the s debar that fo ows
Attached properties
Attached propert es are an nterest ng feature of XAML They are used for severa purposes, but
the one that you w encounter most s ett ng a ch d e ement spec fy a va ue for a property
that actua y be ongs to the parent For examp e, the Grid.Column property that the buttons are
us ng n the prev ous examp e s referr ng to the Column property on the Grid
Suppose that you have the fo ow ng defin t on n the XAML
<Button x:Name="btn1" Grid.Row="1" .../>
In code, th s w
be rendered someth ng ke th s
Grid.SetRow(btn1, 1);
You are nform ng the Grid that btn1 s go ng to be n row 1, but t ooks ke youre sett ng a
property on the Button tse f
The VariableSizedWrapGrid s a var ant on the Grid It a so ays tems out n rows and co umns but
w automat ca y wrap tems to the next row or co umn as necessary Th s s obv ous y usefu when
the v ew ng area s ze changes, such as when sw tch ng your tab et from andscape to portra t mode
The fo ow ng mage shows five Button contro s n a VariableSizedWrapGrid
The hor zonta or entat on shows that th s contro w ay ts ch dren out n rows, and the MaximumRowsOrColums says that t w wrap at three tems To ach eve a n ce ayout, each gr d ce s 150
w de, and the buttons are centered w th n the r ce s If you dec de that you want a ayout that ooks
more ke the W ndows 8 Start screen, you cou d change the XAML to the fo ow ng
<VariableSizedWrapGrid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"
MaximumRowsOrColumns="3" Orientation="Horizontal" ItemWidth="150" ItemHeight="150" >
<Button Content="First" FontSize="24" Background="Blue" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"/>
<Button Content="Second" FontSize="24" Background="Green" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"/>
The d fference s that both he ght and w dth have been set, and the hor zonta and vert ca a gnments have been set to Stretch, so that the tems w fi the r respect ve ce s You can c ear y see the
d fference n the fo ow ng mage
The ast ayout contro we cons der s the Canvas W th th s contro , you can spec fy abso ute
pos t ons for ts ch dren, but t snt used as often as the others because t doesnt adapt automat ca y
to chang ng d sp ay cond t ons Here s an examp e of some Buttons a d out on a Canvas
You can see that the pos t ons of the Buttons are g ven by the Canvas.Left and Canvas.Top attached
propert es The objects are d sp ayed n the order n wh ch they are dec ared, resu t ng n the th rd
Button over app ng the second If you want to spec fy the order ng exp c t y, you can use the ZIndex
property to determ ne the order n wh ch e ements w be rendered
Event handling
When creat ng a UI n XAML, you use attr butes on contro s to nk events to event hand ng funct ons,
such as n the fo ow ng examp e
<Button Content="Click!" Click="Button_Click"/>
Here, the Buttons c ck event s be ng hand ed by a funct on ca ed Button Click n the assoc ated
code-beh nd fi e Reca the examp e of an event hand er funct on n the He oXam that you saw
ear er
void HelloXaml::MainPage::Button_Click_1(Platform::Object^ sender,
Windows::UI::Xaml::RoutedEventArgs^ e)
Every event hand er has the same s gnature the return type s vo d, the first argument s a hand e
to the object that ra sed the event, and the second s a hand e to an object, of type RoutedEventArgs
or one of ts subc asses, wh ch m ght ho d nformat on about the event For examp e, hand ers for keyboard events w be sent a KeyRoutedEventArgs object whose Key property nd cates wh ch key was
pressed In the case of s mp e c ck-type not ficat ons, there s no other nformat on, so you can gnore
th s argument
Note Visual Studio will generate a handler for you, whose name is based on the control
and event names, as in the previous example, but this is simply a convention, and you are
free to use any name you like for event handlers.
The word routed n RoutedEventArgs refers to the fact that events can be routed to more than
one contro Cons der the examp e you saw ear er n the chapter, n wh ch a Buttons content cons sted of a StackPanel conta n ng an Image and a TextBlock If you c ck the Image, youre actua y c ck ng
an Image on top of a StackPanel on top of a Button, and you probab y want to hand e th s event n
the Buttons c ck hand er The event s first passed to the Image Then, ts passed to ts parent (the
StackPanel), and so on, bubb ng up the tree unt t e ther reaches the top or someone says theyve
hand ed t
Th s means that you cou d wr te W ndows Store apps n standard, unmanaged C++, but youd have
to prov de a ot of housekeep ng code to work w th the under y ng Component Object Mode (COM)based nfrastructure For th s reason, M crosoft dec ded to add some extens ons to C++ to hand e
these housekeep ng tasks, n part cu ar manag ng object fet mes
Note If you dont want to use the C++/CX extensions, you can still write WinRT apps in C++
by using a library called Windows Runtime Library (WRL). This can be useful if you want to
access low-level features not exposed by C++/CX, but it is more complex to use and beyond
the scope of this book.
Un ke C++/CLI, C++/CX does not support garbage co ect on Th s means that objects wont move
around n memory, and so nterop w th unmanaged code s eas er, and you can eas y m x C++/CX
and nat ve C++ types
You m ght a so wonder where C++/CLI and NET fit nto the new wor d of W ndows RT app cat ons
It turns out that C++/CX app cat ons can use a subset of the NET APIs, and there s a c ent profi e
prov ded n V sua Stud o so that you can code aga nst th s subset Th s makes t poss b e for NET
deve opers to wr te W ndows RT app cat ons by us ng fam ar APIs
Windows RT
W ndows RT s a new runt me on top of the W ndows kerne It doesnt use W n32 It s comp ete y
new It covers the same funct ona ty as W n32 (wh ch was ntroduced n 1993!) but s object-or ented
and wr tten n C++
The W nRT APIs conta n a subset of the W n32 and COM APIs You can use W nRT APIs from severa
anguages, and anguage b nd ngs are now ca ed projections There are current y three project ons
ava ab e nat ve (for C++), JavaScr pt, and NET (for C# and VB NET)
Metadata
A W nRT objects support reflect on through metadata, so they can be used from dynam c anguages
such as JavaScr pt W nRT uses the same metadata format as the CLR, wh ch makes t eas er and faster
to use W nRT APIs from NET w thout hav ng to use P/Invoke
W nRT code comp es down to nat ve code, wh ch has no fac ty for nc ud ng metadata For th s
reason, the metadata for W nRT code res des n separate fi es w th a w nmd extens on These are
CLI assemb es conta n ng on y metadata, so you can nspect them by us ng the IL d sassemb er too
(ISDASM)
C++/CX syntax
C++/CX s a ghtwe ght set of extens ons to C++, so there snt too much to cover n th s sect on To
create an object, use the ref new keyword, as demonstrated n the fo ow ng
390Microsoft Visual C++/CLI Step by Step
The caret (^) s the same symbo used for managed hand es n C++/CLI, but these are d fferent
because they are po nt ng to unmanaged code We need a hand e here rather than a po nter because
C++/CX objects are reference counted
Observe the use of ref new to create objects Th s s an examp e of a compound keyword, formed
of two separate tokens, and s not s mp y new w th a ref mod fier
Reference counting
The COM mechan sm that under es W nRT uses a system of reference count ng to manage
object fet mes Each t me c ent code obta ns a hand e to an object, the object ncrements
ts reference count When the c ent has fin shed w th the object, t needs to decrement the
reference count When the count reaches zero, the object knows that no one has a reference to
t anymore, and so t can destroy tse f In the past, t was up to deve opers to ensure that reference counts were ma nta ned correct y, and th s was a common source of error The W ndows
Runt me now manages th s for you, so you no onger need to be concerned about object
fet mes
Classes
You create run-t me c asses by us ng the ref keyword, as you do w th C++/CLI
public ref class MyClass
{
};
Note The lack of support for partial classes in C++/CLI is one of the reasons why it is not
simple to create WPF applications in that language by using Visual Studio.
Heres how you m ght use a part a c ass In the fo ow ng examp e, one part s dec ared by us ng
the partial keyword and p aced n ts own header fi e
// MyClass.private.h
#pragma once
partial ref class MyClass
{
private:
int _implementationDetail;
};
The second part of the c ass s p aced n another header fi e that nc udes the first one
// MyClass.h
#pragma once
#include "MyClass.private.h"
ref class MyClass // don't use the 'partial' keyword here
{
public:
int GetDetail();
};
Anyone w sh ng to use the c ass w nc ude MyC ass h, but the nterest ng po nt s that anyone
mp ement ng the pub c part of the c ass doesnt have to see or know any deta s about the pr vate
part
When V sua Stud o creates the code for a XAML user nterface, t generates h and cpp fi es You
w find that the h fi e (for examp e, MyPage h) nc udes another header (MyPage g h) The g h fi e s
the part a c ass generated by the des gner conta n ng the pr vate part of the page defin t on, whereas
the h fi e s the pub c part that you can ed t As you m ght expect, there s a so a g cpp fi e, wh ch
conta ns the mp ementat on of the funct ona ty defined n the g h fi e
Generics
C++/CX supports run-t me gener cs, just ke those youve met n C++/CLI
generic <typename T>
public ref class List
{
property T item;
...
};
The generic keyword ntroduces a gener c type, and the typename n ang e brackets shows that T s
the type parameter wh ch s used n the body of the c ass
Strings
Whereas n C++/CLI code you use a System::String to represent str ngs, n C++/CX you use a
Platform::String Both types of str ng prov de the same bas c funct ona ty, and both are mmutab e
You create a str ng ke th s
String ^s = "First string";
Quick reference
To
Do This
CHAPTER 21
be ab e to
n th s chapter you w create a more comp ex W ndows Store app, one that uses a touch nterface,
and wh ch can be dep oyed onto any M crosoft Surface tab et dev ce As we as show ng you how to
create a rea st c W ndows 8 app, you w a so earn about some of the new features that the W ndows
Store nterface has added to W ndows programm ng
397
As you des gn and code th s app, you w see how apps w th a graph ca UI ke th s are often not
that comp ex n what theyre do ng, but you need to expend some effort to ensure that the UI works
n the correct way For examp e, f the user has se ected b nary mode, on y the 0 and 1 number
keys shou d be enab ed When he sw tches to hexadec ma , the keys 0 through 9 and A through
E shou d be enab ed
Note There are a lot of features that you need to considerand lots of ways of implementing themwhen designing a touch-based app for the Windows Store and the Microsoft
Surface tablet, and we cant consider all of them without turning this chapter into a book.
That means that this app is going to be limited in several respects. First, it is only going to
be a single page app. Second, it is designed for use in landscape orientation only; the UI
does not adapt itself to portrait mode.
1. Start V sua Stud o 2012 and create a new b ank XAML project named ProgCalc
2. In the ed tor, open Ma nPage xam
3. To create an area where the numbers you enter and the resu ts of ca cu at ons are d sp ayed,
drag a Border from the Too box to the ma n page, pos t on ng t at the top w th a eft marg n
of about 430 and a top marg n of about 50 Use the hand es to res ze the area to approx mate y 90 un ts h gh by 730 un ts w de, set ts BorderThickness property to 2, and then set
BorderBrush to Gray (or any other co or you ke)
The numbers you enter nto the ca cu ator are go ng to be d sp ayed n a TextBlock, and t
wou d ook good to g ve the TextBlock a border The way you do th s n XAML s not obv ous
you add a Border contro to represent the border, and then p ace the TextBlock ns de t
4. Drag a TextBlock to the form and drop t nto the Border; you shou d find that t expands to fi
the Border contro Add the x:Name attr bute to g ve t a name so that you can nteract w th
t n the code Ive ca ed t txtOutput You shou d a so remove the Text attr bute from the
XAML and set ts FontSize property to a su tab e va ue such as 72
Note For this particular app, you actually dont need to give the Border a name,
because you arent going to interact with it from code. Only those UI elements with
which you interact need to have a name.
Dont worry about the exact s zes and pos t ons Where the buttons are and how they ook
snt mportant to the funct on ng of the app
5. Drag buttons to the page to start bu d ng up the gr d The buttons d sp ay w th a preset sty e,
but they are rather sma for a ca cu ator I ed ted the propert es to make them 100 w de by
108 h gh, and gave them a font s ze of 72 Ensure that you use the x:Name property to g ve
each button a descr pt ve name, such as btnOne You shou d end up w th a gr d pos t oned
underneath the Border, and eft a gned w th t, s m ar to the fo ow ng screen shot
6. Bu d and run the app to check that everyth ng s OK Start t by press ng Ctr +F5 or, on the
ert es tab at the s de of the V sua Stud o w ndow and then c ck the ghtn ng-bo t button at
the upper-r ght of the ed tor to d sp ay the events for the button
Tip If the Properties tab is not visible, you can open the Properties editor by selecting Properties Window from the View menu or pressing Ctrl+W and then P.
2. In the st of events, find the Click entry, wh ch shou d be at the top Type NumberButtons
You first need to cast the sender hand e to a Button, so that you can use ts Content property,
wh ch ho ds the d g t you want You then need to cast the Content to a String Buttons can have
a sorts of th ngs as content, but n th s case you know that t s a str ng, so the cast s safe
3. Add the same hand er to a 10 number buttons
You can e ther do th s by us ng the Property ed tor or by ed t ng the XAML, add ng a Click
attr bute to the e ements for each button The advantage to do ng t th s way s that you can
cut and paste the text rather than hav ng to type t n the ed tor
4. Bu d and run the app
You can c ck the number buttons to bu d up a number as a str ng n the TextBlock And wh e
were th nk ng about the d sp ay, ets add the og c for the Clear button A th s needs to do
for now s to c ear the str ng n the d sp ay
5. Se ect the Clear button n the XAML, open the Propert es ed tor, and then d sp ay the event st
6. Add a hand er ca ed ClearButton Click to the Click event and then press Enter
Get the str ng from the d sp ay, convert t to a number, and then store t as the eft operand
Tip An easy way to do this is to duplicate a line in the XAML, and then edit it accordingly. For example, I copied the 3 button, renamed it to btnPlus and changed
the Content to +. You can then select it and drag it to the right to position it correctly; the designer will show you when buttons are aligned correctly.
2. To d fferent ate the ar thmet c buttons from the number keys, ass gn them a co or
You can do th s by sett ng the Foreground property, e ther through the Property ed tor or by
ed t ng the XAML d rect y (I set my buttons to LightGreen )
3. When you have added a four buttons, p ck one and d sp ay ts events n the Property ed tor
Type ArithmeticButtons Click as the hand er name and then press Enter
V sua Stud o adds an empty hand er for you
4. Ed t the other three ar thmet c operat on buttons so that they use the same hand er
2. Add code to the hand er to convert the text to an int and store t n the leftOperand
void ProgCalc::MainPage::ArithmeticButtons_Click(Platform::Object^ sender,
Windows::UI::Xaml::RoutedEventArgs^ e)
{
String ^txt = txtOutput->Text;
int val;
swscanf_s(txt->Data(), L"%d", &val);
leftOperand = val;
}
There are a number of ways to perform the string-to-int convers on, and the one Ive used
here w s mp fy us ng other number bases ater n the program The swscanf s funct on takes
a str ng and converts t accord ng to a format The first argument s the raw str ng, wh ch you
can get from the String object by us ng ts Data funct on The second argument s the format
str ng The ead ng L denotes a w de character (as opposed to an ASCII) str ng tera , and %d
a erts the funct on to expect a str ng that represents a dec ma nteger F na y, the &val passes
the address of the var ab e where the resu t shou d be wr tten
Note There are two versions of sswscanf: swscanf and swscanf s. You should always use the
second of these because it does extra checking on its arguments and is less open to misuse,
either accidental or deliberate.
w th n the namespace
namespace ProgCalc
{
enum class ArithOp
{
PLUS, MINUS, TIMES, DIVIDE, NONE
};
public ref class MainPage sealed
{
};
}
The enum has one member for each operat on, p us one to nd cate that there s no operat on
The names fo ow convent on by be ng n cap ta s
2. Add a pr vate member to the MainPage c ass to represent the current operat on
ArithOp currentOp;
3. Open the Ma nPage xam cpp fi e and set the operat on to NONE n the constructor, p ac ng t
4. You can now see wh ch button was pressed Ed t the ArithmeticButtons Click funct on to set
5. C ear the d sp ay by sett ng the Text property for the TextBlock to an empty str ng
6. Bu d the app to ver fy that there are no errors
You cant see any resu t at th s stage, but you can f you want run the app n the debugger,
sett ng a breakpo nt n the ar thmet c button hand er to check that the convers on s work ng
Tip Checking that your code works by using the debugger is recommended practice.
Writing output by using Console::WriteLine isnt!
Performing calculations
You can now comp ete the bas c funct ona ty by mp ement ng the og c beh nd the Equa s button
The operat ons you need to perform are as fo ows
EqualsButton Click
2. Add checks at the start of the hand er to determ ne f there s anyth ng to do
if (currentOp == ArithOp::NONE) return;
if (txtOutput->Text->Length() == 0) return;
You rea ze that you need to use the same code that you mp emented n the ar thmet c
button hand er, but th s wou d ead to dup cat on As a ru e, any t me that you see dup cated
code, you shou d cons der pu ng t out nto a separate funct on, a process ca ed refactoring
Open the Ma nPage xam h fi e and add the prototype for a funct on ca ed ConvertTextToInt,
p ac ng t ns de the namespace
int ConvertTextToInt(Platform::String ^str);
ProgCalc::ConvertTextToInt(Platform::String ^str)
int val;
swscanf_s(str->Data(), L"%d", &val);
return val;
Note There is nothing in the way of error checking here because were sure that the
only content of the string is digits, so conversion should not fail. This is reasonable
for a tutorial example such as this, but in a real app youd want to check that the
user hadnt entered a number too large to fit in an integer.
5. Rep ace the or g na code n the ar thmet c button hand er w th a ca to your new funct on,
ke th s
leftOperand = ConvertTextToInt(txtOutput->Text);
works as expected
4. Add t on, subtract on, and mu t p cat on are s mp e, but you need to guard aga nst d v d ng
by zero If you find that you are about to th s, d sp ay an error message and return
case ArithOp::DIVIDE:
if (rightOperand == 0) {
txtOutput->Text = "Divide by zero";
Reset();
return;
}
result = leftOperand / rightOperand;
break;
Observe the ca to Reset If you get a d v de by zero, you cant cont nue; you want to abandon
the ca cu at on and reset everyth ng But, because th s can nvo ve severa operat ons, t makes
sense to put t n a separate funct on
408Microsoft Visual C++/CLI Step by Step
5. Add the fo ow ng dec arat on of the pr vate Reset funct on to the MainPage c ass n
The funct on c ears the operat on and saved eft operand The clearOnNextKey var ab e he ps
w th contro ng the UI At present, the TextBlock s c eared when you press an operator key,
ready for you to enter a new number What we want to do n th s case s to eave the message
on the d sp ay and not c ear t unt the user taps a number key
7. Add the fo ow ng code to the start of NumberButtons Click
if (clearOnNextKey == true) {
txtOutput->Text = "";
clearOnNextKey = false;
}
8. After youve done that, you can comp ete the equa s hand er, turn ng the resu t nto a str ng
Note Development is often like this: you start implementing one piece of code and
find that there are things you need to do before proceeding. Sometimes it feels as
if youre moving backward, finding that in order to do A, you need to do B, which
requires C, and so on. But, eventually you do get back to A again!
wchar_t buff[80];
swprintf(buff, 80, L"%d", result);
txtOutput->Text = ref new String(buff);
Th s code uses swprintfwh ch does the oppos te to the swscanf s funct on that you earned
about ear ertak ng a va ue and convert ng t to a str ng n a g ven format Un ke swscanf s,
swprintf needs an array of wchar t, wh ch you need to convert to a Platform::String n order to
use t w th the TextBlock
Many deve opers make the m stake of on y test ng the first category, not th nk ng about what m stakes the user cou d make, wh ch means that surpr ses m ght be eft n the code for users to find ater
A good p ace to start s by mak ng a st of what you want to test Dont worry about th nk ng of
everyth ng stra ght off; f another test occurs to you, add t to the st A first obv ous test s for add t on add ng two numbers resu ts n another number that represents the r sum If you test th s w th,
say, 1 + 2 and 3 + 3, there s no reason to suspect that other numbers w behave d fferent y The
same s true of the other ar thmet c operators, so we can start w th the fo ow ng four tests
D v s on of two numbers
Two th ngs mmed ate y spr ng to m nd when I ook more c ose y at th s st A subtract on such as
5 8 w y e d a negat ve number, so I need to test that th s d sp ays correct y I a so rea ze that I
have to test for d v s on by zero, so I add that one My st now ooks ke th s
D v de-by-zero resu ts
n correct error
Another th ng occurs to me gett ng zero nvo ved n ca cu at ons s not just a spec a case for d v s on Mu t p y ng by zero resu ts n zero, and add ng or subtract ng zero a so has to be cons dered
And so we now end up w th the fo ow ng
Mu t p
D v de-by-zero resu ts
n correct error
That w do for the bas c operat on of the ca cu ator Now, you need to th nk about the operat on
of the user nterface Here are a few examp es
Does the C ear button return the ca cu ator to ts start ng po nt whenever t s pressed?
There are a number of other cond t ons that you cou d add, and you shou d ensure that you test as
many as you can before cont nu ng
Automating tests
To ver fy that you havent broken anyth ng, and that your code st works as expected, you
shou d dea y run your tests every t me you make a change to the code It s obv ous y not dea
to have to test your app manua y each t me, so good pract ce recommends automat ng the
test ng of app cat ons For test ng nd v dua funct ons and c asses, V sua Stud o nc udes too s
w th wh ch you can create a su te of un t tests and run them w th the c ck of a button
It s s ght y more comp ex to test UIs, but W ndows RT prov des ways to automate the
execut on of your app cat ons Us ng them, you can wr te scr pts to s mu ate press ng buttons
and then see what the state of the app s D scuss ng how to do th s s beyond the scope of th s
book, but you can find more deta s on the Internet, nc ud ng http://blogs.msdn.com/b/
windowsappdev/archive/2012/09/04/automating-the-testing-of-windows-8-apps.aspx
If youre go ng to subm t your app to the W ndows Store, you need to prov de severa ogos and
mages At a m n mum you need to prov de the fo ow ng
The store ogo (50x50 p xe s), used to d sp ay your app n search st ngs n the W ndows Store
The sma ogo (30x30 p xe s), used w th your apps d sp ay name n var ous p aces, such as n
search resu ts and n sts of searchab e apps
The sp ash screen (620x300 p xe s) that d sp ays wh e your app s start ng up
Because youre not go ng to subm t th s part cu ar app to the W ndows Store, you dont need to
create a of these But we w address two of them to make the ca cu ator ook a b t more rea st c
Note The Manifest Editor has several entries for some of the logos under the heading
Scaled Assets. To get the best UI experience, Microsoft encourages designers to provide
properly scaled versions of the various image files because these will look much better than
scaling them programmatically.
There are two ways n wh ch you can prov de a ogo the first s to ed t the defau t graph c created
for the project, and the second s to create another graph c and mport t To ed t the ogo, n So ut on
Exp orer, doub e-c ck the Logo png fi e Th s opens the fi e n the bu t- n graph cs ed tor I created the
ogo shown n the fo ow ng ustrat on by us ng a pa nt program; you can use any program you ke,
prov ded you can produce an mage that s 150x150 p xe s and saved as a Portab e Network Graph cs
(PNG) fi e
To use t to represent your app, copy t nto the Assets fo der for your app Then, open the Man fest
Ed tor, and type the name of the fi e nto the Logo box, as demonstrated n the fo ow ng screen shot
Observe the Background Co or entry n the ed tor A though you can use any mage you want for a
t e, t s very common to use wh te graph cs on a co ored background, and to make the mage background transparent Th s makes t poss b e for users to change the background co or of t es, wh e st
ma nta n ng a cons stent ook Heres how the app ooks on the Start screen now
You can see that the custom ogo appears a ongs de the t es of other apps, and that the name of
the app has been added to the t e You can contro whether th s name s d sp ayed, because you ke y
wou dnt want t to f your ogo nc udes the app name
The sp ash screen s d sp ayed wh e the app s start ng up It cons sts of an mage 620x300 p xe s
that s d sp ayed on a co ored background Aga n, the mage s often created w th a transparent background so that users can change the W ndows background co or After you have created an mage of
the correct s ze, n the man fest Ed tor, n the pane on the eft, c ck Sp ash Screen and then type the
name of the mage fi e nto the text box Rebu d and run the app; you shou d see the sp ash screen
appear before the ca cu ator nterface opens
You p ck a badge from a m ted set of 11 symbo s and the numbers from 0 to 99 (any number greater than 99 d sp ays as 99+) In the current vers on of W ndows, you cant define your
own badges As w th content, app badges can be updated by background processes
3. Add three buttons next to the ar thmet c operat on keys and under the E key Labe them
dec, hex, and b n, from the top downward, and g ve them the names btnDecimal, btnHex
and btnBinary You need to decrease the font s ze for the text to fit on the buttons, and you
can change the co or to make them stand out Refer back to the first figure n th s chapter to
see what the arrangement ooks ke
4. You need to a way to determ ne wh ch base youre us ng, so add a TextBlock to the r ght of
choos ng from a sma set of va ues, so another enum s appropr ate Open Ma nPage xam h
and add an enum w th n the namespace
namespace ProgCalc
{
enum class Base
{
DEC, HEX, BIN
};
...
};
2. Add a data member to the MainPage c ass to ho d the current base, and n t a ze t to dec ma
// In MainPage.xaml.cpp
void ProgCalc::MainPage::Reset()
{
currentOp = ArithOp::NONE;
base = Base::DEC;
leftOperand = 0;
clearOnNextKey = true;
}
You can see how each of the cases sets the base var ab e and d sp ays the current base n the
TextBlock The comments about enab ng buttons are there as p aceho ders, because th s s
another examp e of code that s best prov ded as separate funct ons
4. Add three new members to the MainPage c ass dec arat on n Ma nPage xam h
void EnableHexButtons(bool enable);
void EnableDecimalButtons(bool enable);
void EnableBinaryButtons();
Not ce the s ght y d fferent form of the b nary funct on Ive added the Boo ean argument to
the dec ma and hexadec ma funct ons to he p avo d code dup cat on
The dec ma and hexadec ma funct ons enab e or d sab e the 0 through 9 and A through F
keys, respect ve y The b nary funct on on y wants the 0 and 1 keys, so the eas est so ut on s to
d sab e everyth ng and turn on the ones you want
6. Ca them from the base hand er For the b nary case, just ca EnableBinaryButtons For the
dec ma case, ca EnableDecimalButtons(true) and EnableHexButtons(false), and for the hexadec ma case, ca both the dec ma and hex funct ons w th true as the argument
if (btn == btnDecimal)
{
// Enable the decimal buttons
EnableDecimalButtons(true);
EnableHexButtons(false);
base = Base::DEC;
txtBase->Text = "dec";
}
be reset to dec ma
void ProgCalc::MainPage::Reset()
{
currentOp = ArithOp::NONE;
base = Base::DEC;
txtBase->Text = "dec";
leftOperand = 0;
clearOnNextKey = true;
EnableDecimalButtons(true);
EnableHexButtons(false);
}
n t a ze proper y
Get the str ng from the d sp ay and convert t to a va ue, us ng the current number base
Convert the va ue to a str ng, us ng the new number base, and put t back n the d sp ay
The first step s to mod fy the ConvertTextToInt funct on that you wrote ear er so that t takes
account of the number base Convert ng from dec ma and hexadec ma str ngs can be done by
swscanf s, but you need to do b nary yourse f
now a member of the MainPage c ass so that t has access to members of the c ass
int ProgCalc::MainPage::ConvertTextToInt(Platform::String^ s)
{
int n;
if (base == Base::HEX)
swscanf_s(s->Data(), L"%x", &n);
else if (base == Base::DEC)
swscanf_s(s->Data(), L"%d", &n);
else if (base == Base::BIN)
n = FromBinary(s->Data());
return n;
}
The %x descr ptor converts a hexadec ma str ng, and %d hand es the dec ma case You w
prov de your own funct on to dea w th the b nary convers on
2. Add a prototype for the FromBinary funct on to Ma nPage xam h Because th s s a ut ty
funct on and doesnt need access to any members of the MainPage c ass, you dont have to
make t a member
unsigned long FromBinary(std::wstring s);
Th s funct on uses the wcstol (W de Character Str ng To Long) funct on for the convers on,
wh ch w cope w th nput str ngs n b nary Here s where you see a good examp e of the
many str ng convers ons that you m ght need to use n W ndows programm ng the Data
funct on gets a wstring out of the Platform::String, and the c str funct on then gets a wchar t*
that represents the content of the wstring
Not ce the second argument to the funct on Th s returns a po nter to where the number
stopped n the str ng that you passed n The dea s that the funct on w convert as much
of the str ng as t can to a number and then stop when t reaches a character t cant hand e;
t w then pass you back a po nter to that character, so you can p npo nt where pars ng
stopped Because we know that the ent re str ng s va d, we dont need to use that argument,
but we must st supp y a var ab e
4. You now need to do the oppos te convers on, tak ng a va ue and convert ng t to a str ng n
the correct format Add a prototype for th s funct on to the header fi e, such as shown n the
fo ow ng
Platform::String^ ConvertOutputString(int val);
You can see that the structure of th s funct on now m rrors that of ConvertTextToInt It a so
uses another he per funct on ca ed ToBinary to convert a va ue to a b nary str ng
6. Add the prototype for ToBinary to Ma nPage xam h
String^ ToBinary(int n);
Th s funct on g ves you a chance to use the b tw se operators, wh ch s not someth ng you
have to do very often, so t s worth tak ng the opportun ty to use them here The do oop
exam nes the code, b t by b t, add ng a 1 or 0 character to a str ng, depend ng on whether
the b t s set or not The express on (n & 1) does a b tw se AND of the va ue and 1 Remember
that the AND takes two nteger va ues for each b t pos t on, return ng 1 f (and on y f) both
are set Because 1 on y has a s ng e 1 n the owest b t pos t on, th s s check ng whether the
owest b t s set
The oop cond t on (n >>= 1) does a r ght-sh ft on the va ue by one pos t on Th s sh fts a the
b ts one p ace to the r ght, os ng the r ghtmost b t, so that b t 2 becomes b t 1, and a zero s
ntroduced on the far eft to fi n After the oop has exam ned a the b ts, the number w be
eft as a zeros, so the oop w term nate
At th s po nt, however, the str ng s n the wrong order because the character represent ng the
owest b t s the first, and the others have been added on So, you need to reverse the str ng;
you cou d do th s by us ng a oop, but the Standard L brary has a usefu reverse funct on, so
you can use that, nstead
Note The way binary conversion is handled here is limited. In particular, because
binary representations are much longer than their decimal or hexadecimal equivalent, it would be easy to generate a number that would overflow the space in the
TextBlock.
8. The fina stage s to comp ete the og c for chang ng base and updat ng the d sp ay Add code
to the start of the BaseButtons Click hand er to get the number from the d sp ay, as
here
// Get the value from the display
int val = 0;
if (txtOutput->Text->Length() > 0)
val = ConvertTextToInt(txtOutput->Text);
9. After chang ng the base, put the va ue back n the new format
// Update the display
txtOutput->Text = ConvertOutputString(val);
clearOnNextKey = true;
ustrated
if (btn == btnDecimal)
{
EnableDecimalButtons(true);
EnableHexButtons(false);
base = Base::DEC;
txtBase->Text = "dec";
}
else if (btn == btnHex)
{
EnableDecimalButtons(true);
EnableHexButtons(true);
base = Base::HEX;
txtBase->Text = "hex";
}
else if (btn == btnBinary)
{
EnableBinaryButtons();
base = Base::BIN;
txtBase->Text = "bin";
}
// Update the display
txtOutput->Text = ConvertOutputString(val);
clearOnNextKey = true;
}
wchar_t buff[80];
swprintf(buff, 80, L"%d", result);
txtOutput->Text = ref new String(buff);
These are areas that appear when the user sw pes from top or bottom of the screen (or by r ghtc ck ng or typ ng Ctr +Z) They are not ntended to ho d cr t ca commands the dea s that anyth ng
cr t ca ( ke the take a p cture command for a camera app) ought to be n the ma n UI
App cat ons can have two app bars one at the top of the screen, wh ch s typ ca y used for
nav gat on, and one at the bottom, wh ch s used for commands In th s sect on, you add a bottom
app bar to the ca cu ator, wh ch w ho d three buttons, g v ng you an a ternat ve way to change the
number base Here s what the app w ook ke w th the app bar d sp ayed
Styles
One of the secrets to des gn ng great W ndows Store apps s to use a coherent and cons stent
v sua sty e throughout Th s s done n XAML through the bera use of sty es, wh ch work n a
s m ar way to how CSS does n HTML A deve oper or des gner can define a sty e for buttons
that estab shes the bas c appearance, nc ud ng co ors, fonts, borders, and other propert es
Th s sty e can then be app ed across the app, and a form of nher tance means that adjustments can be made Do ng th s makes t poss b e for sty es to be shared across pages and even
across app cat ons, and prevents dup cat on n the XAML A W ndows Store project comes w th
a fi e ca ed StandardSty es xam , wh ch defines a base set of sty es for W ndows Store apps You
shou d use these when you can so that your apps b end w th the W ndows Store ook and fee
Th s s fo owed by a ot of commented out entr es wh ch define sty es for var ous buttons
2. Copy one of the sty e entr es, remove the comments, and then ed t t so that t ooks ke th s
<Style x:Key="HexAppBarButtonStyle" TargetType="ButtonBase"
BasedOn="{StaticResource AppBarButtonStyle}">
<Setter Property="AutomationProperties.AutomationId" Value="HexAppBarButton"/>
<Setter Property="AutomationProperties.Name" Value="Hex"/>
<Setter Property="Content" Value="h"/>
</Style>
Th s creates a sty e for the Hex button, wh ch s based on the defau t AppBarButton sty e and
whose content s an h The Name s the text that w be d sp ayed be ow the button when t
appears on the app bar
3. Repeat the prev ous step to create sty es for the dec ma and b nary buttons
<Style x:Key="DecAppBarButtonStyle" TargetType="ButtonBase"
BasedOn="{StaticResource AppBarButtonStyle}">
<Setter Property="AutomationProperties.AutomationId" Value="DecAppBarButton"/>
<Setter Property="AutomationProperties.Name" Value="Dec"/>
<Setter Property="Content" Value="d"/>
</Style>
<Style x:Key="BinAppBarButtonStyle" TargetType="ButtonBase"
BasedOn="{StaticResource AppBarButtonStyle}">
<Setter Property="AutomationProperties.AutomationId" Value="BinAppBarButton"/>
<Setter Property="AutomationProperties.Name" Value="Bin"/>
<Setter Property="Content" Value="b"/>
</Style>
the bottom of the screen You shou d see the app bar appear C ck or touch anywhere e se on
the screen (or sw pe downward), and t w s de away
Hooking it up
You now have an app bar that you can d sp ay and h de, but t doesnt do anyth ng Fortunate y, ts a
s mp e matter to ed t the base buttons hand er so that t reacts proper y to the app bar buttons
1. Ed t the code n the BaseButtons Click funct on so that t accepts both the button on the
Adding sharing
For the fina task n th s chapter, youre go ng to add another feature to the ca cu ator the ab ty
to share data w th other app cat ons Th s snt go ng to be very soph st cated, because youre on y
go ng to be ab e to share the va ue n the d sp ay, but t ustrates an mportant feature of W ndows
Store apps
Share The app can share content w th other app cat ons or s ready to accept spec fic types
of data from other app cat ons
Play To The app can stream aud o, v deo, and mages to enab ed dev ces
File Picker The app s used as a ocat on for sav ng and oad ng fi es
Cached File Updater The app can track fi e updates and de ver the atest vers on to
theuser
Charms are a spec fic and cons stent set of buttons that you can access n every app The charms
are Search, Share, Connect, Sett ngs, and Start They appear on the r ght s de of the screen when you
sw pe nward from the r ght edge of the screen, move the mouse po nter to the upper-r ght or owereft of the screen, or press W ndows key+C
These buttons prov de the fo ow ng set of core act ons that users frequent y need
Search for content ocated n your app or n another app, and search your apps content from
another app
As you can apprec ate, mp ement ng contracts and us ng the charms makes your app a fu member of the W ndows Store commun ty
Implementing sharing
Shar ng s one of the common contracts supported by apps, ett ng them share data w th other apps
n a var ety of formats, nc ud ng the fo ow ng
P a n text
Formatted text
HTML
URIs
B tmaps
F es
5. Set up the DataTransferManager so that shar ng s act ve for the app Start by add ng a new
Th s object s returned to you when you reg ster your event hand er w th the DataTransfer
Manager It snt str ct y necessary to nc ude t here, because you on y need t when mp ement ng a mu t page app In that case, you w mp ement the OnNavigatedFrom funct on,
wh ch s ca ed when you move to another page, and youd use the token to te the Data
TransferManager that you no onger want th s page to rece ve share events There s, however,
no harm n nc ud ng t, and t w serve to rem nd you of what to do when you move on to
mu t page app cat ons
6. Add the fo ow ng code to the OnNavigatedTo funct on to reg ster for share events, p ac ng t
Not ce the rather compressed form of the second statement You create a new TypedEvent
Handler, wh ch uses gener cs to create a de egate that w ca a hand er funct on You use the
ang e brackets to spec fy the two argument types that the hand er w use, and then prov de
the funct on that the de egate w ca n th s case, t s the ShareTextHandler funct on on th s
object
The de egate s hooked to the DataRequested event on the DataTransferManager, and th s
returns the token that you can use to unreg ster when nav gat ng away from the page
7. Bu d and run the app and put a number n the d sp ay Then, se ect the Share charm, wh ch s
You can see that the t t e for the data, a ong w th a descr pt on f you supp ed one, s shown
so that users can dec de what they want to do w th the data On the system Im us ng, on y the
Ma app s ab e to accept shared text data
Where next?
Ive run out of space n th s chapter, but now that you have seen how to bu d a more comp ex
W ndows Store app, there are severa ways n wh ch you cou d enhance the ca cu ator, bu d ng on
what youve earned Here are some suggest ons
Add the typ ca ca cu ator memory funct ona ty The ca cu ator keeps a memory var ab e,
and four buttons et you set t to zero (MC), add the current y d sp ayed va ue to t (M+), subtract the current y d sp ayed va ue from t (M), and put the stored va ue nto the d sp ay (MR)
Add a change s gn button (+/) that changes the s gn of the va ue n the d sp ay
Imp ement some more programmer funct ona ty, such as b tw se operat ons (AND, OR, XOR,
and NOT) and eft and r ght sh ft
Add a h story mechan sm so that you can see what youve done up to now
Quick reference
To
Do This
PAR T IV
Advanced topics
CHAPTER 22
437
CHAPTER 23
453
CHAPTER 24
L v ng w th COM
475
435
CHAPTER 22
be ab e to
A though the pr mary focus of th s book s us ng C++/CLI w th the M crosoft NET Framework, at
t mes you have to ca funct ons outs de the NET env ronment
Mixed classes
A though managed c asses are norma y composed of other managed types, t s poss b e to m x managed and unmanaged types as members of c asses under some c rcumstances It s a so poss b e to
have a po nter to an unmanaged object as a member of a managed c ass, as n th s examp e
ref class ManagedClass
{
UnmanagedClass *puc;
...
};
437
Not ce the use of the aster sk (*) rather than the caret (^) th s s a po nter to an unmanaged type,
not a hand e
Because the member s unmanaged, ts up to you to manage the fet me of the object at the other end of the po nter You shou d hand e th s carefu y unmanaged objects somet mes need exp c t
de et on at a part cu ar po nt n the code, and th s m ght not fit we w th the NET garbage co ect on
mode However, you can dec are destructors for managed c asses and use delete on objects of managed types, so ts poss b e to arrange for correct object dea ocat on n most c rcumstances
You cant have an unmanaged object as a member of a managed c ass, such as s
fo ow ng
ref class ManagedClass
{
UnmanagedClass obj;
...
};
ustrated n the
An unmanaged object w on y work as a c ass member f the host object s exp c t y de eted at
some po nt at the end of the enc os ng b ock for an automat c var ab e, at the end of the process for
a g oba var ab e, or when delete s ca ed on a po nter Managed objects dont work n th s way, and
the garbage co ector cant co ect an unmanaged object
Its mposs b e to have a hand e to a managed type as part of an unmanaged c ass, as shown here
class UnmanagedClass
{
ManagedClass ^obj;
...
};
Because the unmanaged object doesnt ex st n the NET wor d, the hand e to the conta ned object
s nv s b e to the garbage co ector Thus, the garbage co ector doesnt know who has a reference to
the object or when t can be co ected
2. Pass the GCHandle to the unmanaged code As ong as the hand e hasnt been freed, the
Manage
2. Add an #include d rect ve for the gcroot h system header fi e just be ow the stdafx h include
d rect ve
#include <gcroot.h>
Services namespace
using namespace System::Runtime::InteropServices;
The defin t on of the mc var ab e s an examp e of us ng a temp ate c ass The defin t on effect ve y creates a gcroot var ab e that wraps a GCHandle to an MClass po nter The GCHandle s
created when the gcroot object s created, and t s freed when the gcroot object s destroyed
A UClass object s passed a hand e to a managed MClass object when t s created, and th s
hand e s stored away n the gcroot object The getValue funct on s mp y returns the pub c val
member from the MClass object by va ue, so you can ver fy that the code rea y ets you access a managed object from an unmanaged context
6. Mod fy the main funct on to use the c asses
int main(array<String^>^ args)
{
Console::WriteLine("Testing...");
// Create a managed object
MClass ^pm = gcnew MClass(3);
// Create an unmanaged object
UClass uc(pm);
Console::WriteLine("Value is {0}", uc.getValue());
return 0;
}
The code first creates a managed object and n t a zes t w th an nteger The po nter to th s
object s then used to n t a ze an unmanaged object, and the getValue funct on s used to
extract the va ue from the managed object before pr nt ng t out When the UClass object
goes out of scope, the gcroot s destroyed, wh ch frees the GCHandle and, n turn, frees up the
managed object
Tip If the managed type that you want to use with gcroot has a destructor, using the
auto gcroot type (declared in <auto gcroot.h>) will call the destructor on the object
when thegcroot goes out of scope.
Interior pointers
Before gett ng to p nn ng, ets br efly d scuss interior pointers We w do th s by ook ng at a scenar o
n wh ch you have a managed object, and you want to pass t to an unmanaged funct on that requ res
a po nter
You probab y know that the garbage co ector can (and does) move objects around on the managed heap to max m ze free space Th s means that you cant use an unmanaged po nter to refer to a
managed object, because the address he d n the po nter cou d end up po nt ng to the wrong p ace f
the garbage co ector moves the object In fact, the comp er w g ve you an error f you try to use an
ord nary po nter w th a managed object
An interior pointer s a po nter whose address w be updated f the object to wh ch t refers s
moved They are ca ed nter or po nters because you use them to po nt to a member w th n a managed object
Note You cant use an interior pointer to point to a whole managed object; you can only
point to a field within an object.
Pinning pointers
The CLR assumes that t can move objects around n the managed heap whenever t wants At t mes,
however, you m ght need to te the CLR to eave objects where they are For examp e, f you want to
pass a po nter to a managed object to an unmanaged funct on, you dont want the CLR to move the
object around n memory wh e the object s be ng used by the unmanaged code
A pinning pointer s a po nter to a managed object, but the va ue of the po nter cannot be
changed, wh ch means that the garbage co ector cannot move t around n memory Thus, creat ng
a p nn ng po nter to an object g ves you a po nter that can safe y be passed out to unmanaged code
because you can be sure that the address s go ng to rema n va d
You can use p nn ng on a or part of a managed object, and p nn ng a member of a managed
object resu ts n the ent re object be ng p nned For examp e, p nn ng the first e ement of an array w
resu t n the ent re array be ng p nned The object w rema n p nned unt there are no references eft
to the p nn ng po nter
The code fragment that fo ows shows the creat on and use of a p nn ng po nter F rst, assume that
we have an unmanaged funct on that takes a po nter to an nteger
void someFunc(int *p)
{
// Do something with the integer value
int n = *p;
}
After the array e ement has been p nned, you can pass ts address to the unmanaged funct on,
confident that the int wont be moved around n memory Observe how there s an mp c t convers on
between pin ptr<int> and int*, so you dont need to convert t yourse f When youre fin shed, ass gnng nullptr to the p nn ng po nter frees the array object so that t can be moved
Va ue types are stored on the stack, un ke references, wh ch are stored on the run-t me heap
Instances of va ue types are a ways accessed d rect y, un ke reference types, wh ch are
accessed through references Th s means that you dont use the new operator when creat ng
nstances It a so means that va ue types are not garbage-co ected
Copy ng va ue types cop es the va ue rather than the reference
Anyth ng that wraps a s mp e va ue, such as a Boo ean or an nteger, and that s ess than about
16 bytes n s ze s a good cand date for mak ng a va ue type Because va ue types arent accessed v a
references, they can be far more effic ent than the equ va ent reference types but cant be regarded
as objects n the same way that reference types can Th s becomes a prob em when you want to use
a va ue type n a context where an object reference s needed For examp e, cons der the over oad of
the Console::WriteLine funct on that performs formatted output, whose prototype s shown here
static void WriteLine(String^, Object^);
The first String^ parameter s the format str ng, and the second s a hand e to any NET reference
type Because va ue types arent accessed by references, you cant d rect y spec fy a va ue type But,
you w find that the fo ow ng works, even though 12 s not an nstance of a reference type
int foo = 12;
Console::WriteLine("foo is {0}", foo);
Boxing
Box ng wraps a va ue type n an object box so that t can be used where an object reference s
needed In C++/CLI, th s wrapp ng s done automat ca y
The fo ow ng three th ngs happen when an object s boxed
Be aware that the managed object conta ns a copy of the va ue type Th s means that any mod ficat ons you m ght make to the managed wrapper dont propagate back to the or g na va ue You can
see th s happen ng f you ook at the generated code the IL d sassemb er too (ISDASM) The IL generated for the preced ng two nes of C++/CLI code ook someth ng ke th s
IL_0002:
IL_0004:
IL_0005:
IL_000a:
IL_000b:
IL_0010:
ldc.i4.s
12
stloc.1
ldstr "Value is {0}"
ldloc.1
box
[mscorlib]System.Int32
call
void [mscorlib]System.Console::WriteLine(string, object)
The first ne pushes a tera 12 onto the stack, and the second ne stores t (stloc) nto a oca var ab e After the str ng tera s pushed onto the stack, the ldloc nstruct on takes the oca var ab e and
pushes t back onto the stack You can see that the next ne s a box nstruct on, wh ch generates an
object to ho d the nteger before ca ng WriteLine
Unboxing
What f you want to retr eve the va ue from a boxed object? The fo ow ng br ef exerc se shows you
how to get the va ue back out of a boxed object by us ng a cast
1. Create a new CLR Conso e App cat on project named Boxing
2. Ed t the main funct on to create an nteger and box t
int main(array<String^>^ args)
{
Console::WriteLine("Boxing Example");
// Create an int
int foo = 12;
// It will get boxed automatically
Object ^obj = foo;
// Use the boxed object
Console::WriteLine("Value of foo is {0}", obj);
return 0;
}
The safe cast checks to see whether a boxed int s on the other end of the obj po nter; f t s, t
returns an int
NoteThe safe cast is explored in Chapter 3, Variables and operators, but lets take
a moment to consider it here. Like dynamic cast, a safe cast is performed at run
time. It checks whether the type on the other end of the handle is of the right type.
If it is, the cast is performed and the value returned. Unlike dynamic cast, which returns a null if the types dont match, safe cast will throw an exception.
4. Bu d and run the app cat on
You need to ca a M crosoft W ndows API funct on that doesnt have a NET equ va ent
You have some code n a Dynam c-L nk L brary (DLL) that or g nated outs de NET and cant be
rewr tten
You have code that needs to be wr tten n a anguage thats not yet supported by the NET
Framework
Whatever the reason, the code youre ca ng ex sts outs de the NET-managed env ronment,
soyou need a way to pass funct on ca s nto and out of NET The mechan sm to do th s s ca ed
P/Invoke (for P atform Invoke, pronounced p- nvoke) It s prov ded to et you ca funct ons n DLLs
Us ng P/Invoke nvo ves add ng a prototype to your code that uses attr butes to nform NET about
the funct on youre propos ng to ca In part cu ar, you need to spec fy the name of the DLL conta nng the funct on, the name of the funct on, what arguments the funct on takes, and what the funct on
returns
A mechan sm such as P/Invoke s necessary to fac tate commun cat on between managed and
unmanaged code Take str ngs as an examp e A str ng n C++/CLI s a hand e to a String object, but
n standard C++, a str ng snt represented by an object Instead, a str ng s a po nter to a ser es of
memory ocat ons that conta n characters and s term nated by a nu If youre go ng to pass a str ng
data between managed and unmanaged code, someth ng has to convert between the correspond ng
managed and unmanaged data types Th s convers on process s ca ed marsha ng, and t s one of
the tasks that P/Invoke performs for you
Identifying functions
There are two po nts that you need to be aware of when dent fy ng funct ons to ca us ng
P/Invoke A though you usua y dent fy a funct on n a DLL by name, you can a so ass gn a
funct on n a DLL a number that can be used to execute the funct on at run t me If you need to,
you can dent fy a DLL funct on to P/Invoke by us ng th s ord na number
When you ca W ndows API funct ons, you can a so have two or more vers ons of funct ons
that take characters or str ngs as arguments because W ndows can support more than one
character encod ng For examp e, standard M crosoft W ndows XP supports both the ASCII (one
byte per character) and Un code (two bytes per character) character encod ngs Th s means
that both ASCII and Un code vers ons of each funct on must ex st, dent fied by an A or a W,
respect ve y, added to the end of the funct on name (for examp e, MessageBoxW) A though
you can ca the d fferent vers ons d rect y, the C++ comp er maps a ca to MessageBox onto
the correct funct on depend ng on whether youre us ng ASCII or Un code n your app cat on
As you d scover n the exerc se ater n th s sect on, you can spec fy wh ch vers on of a
funct on you want to use w th P/Invoke If you dont exp c t y p ck one, the ASCII vers on w
used
be
The fo ow ng exerc se shows you how to ca an unmanaged funct on n one of the W ndows
system DLLs The obv ous cand date for th s exerc se s MessageBox for two reasons first, ts a standa one funct on and doesnt requ re any sett ng up; second, ts obv ous whether the ca has worked
The MessageBox funct onthat s, the MessageBoxA and MessageBoxW funct onsres de n the
User32 d system DLL Three system DLLs conta n the unmanaged W ndows API code
User32 d , wh ch conta ns funct ons for message hand ng, t mers, menus, and
commun cat ons
Kerne 32 d , wh ch conta ns ow- eve operat ng system funct ona ty for memory management and resource hand ng
GDI32 d , wh ch conta ns the GDI graph cs subsystem code
How do you know wh ch DLL ho ds a part cu ar system funct on? If you ook the funct on up n
the P atform SDK, you usua y find a c ue n the Requ rements sect on at the end of the top c For
examp e, the He p top c for MessageBox has the fo ow ng nes
L brary User32 b
DLL User32 d
The first ne nd cates that f you want to use MessageBox n trad t ona C++ code, you have
to nk w th a brary named User32 b, and the second denotes that the code actua y res des n
User32 d
Now that you know where you can find the MessageBox funct on, heres the exerc se
1. Start a new CLR Conso e App cat on project named Message
2. Add a using d rect ve to the top of the project
using namespace System::Runtime::InteropServices;
Most of the nterop features are part of the System::Runtime::InteropServices namespace, and
ts much eas er to use f you dec are the namespace
3. Add the P/Invoke prototype for the MessageBox funct on before the main rout ne
// Set up the import
[DllImport("User32.dll", CharSet=CharSet::Auto)]
int MessageBox(IntPtr hwnd, String ^text,
String ^caption, unsigned int type);
There s qu te a ot to exp a n about these few nes of code The prototype for the Message
Box funct on s dec ared by us ng the DllImport attr bute The two parameters passed to the
attr bute are the name of the DLL n wh ch the funct on res des, and (because th s s a funct on
that uses characters or str ngs) an nd cat on of wh ch vers on to use CharSet::Auto eaves t
up to the target p atform to dec de wh ch vers on to ca and how to convert the str ng arguments
The first argument to MessageBox s a hand e to the own ng w ndow Th s s a hand e n the
or g na W n32 sense, and t s bas ca y a po nter Th s s used to estab sh the MessageBox as a
ch d of another w ndow, and were not concerned about t here The rather strange cho ce of
argument name (hwnd) comes from the or g na type, HWND
NoteAn IntPtr is an integer type large enough to hold a native pointer, so it will be
32 bits on 32-bit Windows and 64 bits on 64-bit systems. It is commonly used in interop to pass pointers to and from unmanaged code.
Not ce how String hand es are used to pass str ng nformat on, where the or g na funct on
wou d requ re a W ndows LPTSTR type The P/Invoke marsha ng automat ca y converts the
data when mak ng the ca The fina argument s the sty e of MessageBox, wh ch governs
wh ch con and buttons t w d sp ay The defau t va ue s zero, wh ch just d sp ays an OK
button
Passing structures
You often need to pass structured data to arguments to unmanaged funct ons, and you must do
th s carefu y In part cu ar, you need to spec fy the way structures are a d out n memory to be sure
that they are passed around correct y You spec fy the ayout of structures and c asses by us ng the
StructLayoutAttribute and FieldOffsetAttribute c asses
You add StructLayoutAttribute to managed types to define a formatted type w th a part cu ar ayout There are three poss b e ayout types that you can spec fy for a formatted type
The fo ow ng exerc se shows how to ca an unmanaged W ndows API funct on that needs to be
passed a structure The funct on s GetSystemPowerStatus, wh ch reports on the AC and battery status
of the system The W ndows API defines a structure SYSTEM POWER STATUS, wh ch conta ns the
status nformat on The defin t on of th s unmanaged structure s shown here
typedef struct _SYSTEM_POWER_STATUS {
BYTE ACLineStatus;
BYTE BatteryFlag;
BYTE BatteryLifePercent;
BYTE Reserved1;
DWORD BatteryLifeTime;
DWORD BatteryFullLifeTime;
} SYSTEM_POWER_STATUS, *LPSYSTEM_POWER_STATUS;
// status
The funct on takes a po nter to a SYSTEM POWER STATUS structure, fi s t n, and hands back the
fi ed structure, return ng a Boo ean va ue to et you know whether t worked Your task s to ca th s
funct on, pass ng over a structure, and then d sp ay the resu ts
1. Create a new CLR Conso e App cat on project named PowerMonitor
2. Add the fo ow ng using d rect ve
using namespace System::Runtime::InteropServices;
Our equ va ent of SYSTEM POWER STATUS s a managed c ass named PStat The or g na defin t on conta ns two W ndows data types BYTE, wh ch represents a one-byte nteger, and so
can be represented by the System::Byte type; and DWORD, wh ch s a 32-b t uns gned nteger,
and so s represented by System::UInt32 The StructLayoutAttribute s attached to the c ass, and
LayoutKind::Sequential s spec fied so that the ayout of the members w rema n the same as
the data s passed through P/Invoke
4. Define the prototype for the GetSystemPowerStatus funct on, as shown here
// Define the BOOL type
typedef int BOOL;
// Prototype for the function
[DllImport("Kernel32.dll", CharSet=CharSet::Auto)]
BOOL GetSystemPowerStatus(PStat ^ps);
BOOL s a W ndows type represent ng a Boo ean va ue and s actua y a typedef for an nteger
It has been w de y used n the W ndows API because C acks a true Boo ean type The prototype uses the rea name of the funct on as t occurs n Kerne 32 d , and the s ng e argument s
g ven as a hand e to our managed type
5. Wr te the code to ca the funct on Ed t the main funct on to create a PStat object and use t
ustrated n the fo ow ng
If the ca worked, the return va ue shou d be nonzero, wh ch represents a Boo ean true va ue
6. Bu d and run the app cat on at th s po nt, correct ng any errors and check ng the output
7. Add code to report on the members of the c ass
The first check s on the ACLineStatus fie d, wh ch w have the va ue 0 (on), 1 (off), or 255
(unknown) The second check s on the status of the battery, and th s va ue can be made up of
one or more of the va ues 1 (h gh charge), 2 ( ow charge), 4 (cr t ca y ow charge), 8 (chargng), and 128 (no battery present) Each of these represents a part cu ar b t pos t on w th n the
resu t, and the b tw se OR operator (&) s used to check wh ch b ts are set
The fina two checks pr nt out the percentage of fet me eft n the battery and the number of
seconds If the funct on cant determ ne the number of seconds, t w return 1 n th s fie d
8. Bu d and run the app cat on You w
aptop
Quick reference
To
Do this
Use safe cast to cast the box ng object to the correct type, and
then dereference the po nter. For examp e:
int myVal = safe_cast<int>(po);
CHAPTER 23
be ab e to
h s chapter ntroduces metadata and attr butes and shows you how to start defin ng and man puat ng metadata for your own NET types
453
The comp er a ways attaches metadata to the output code to descr be t, and the Common
Language Runt me (CLR) uses the metadata to contro the oad ng and execut on of the code You
can a so attach metadata to code by us ng attr butes, wh ch are spec a syntax e ements that can be
attached to c asses and c ass members You see how to use attr butes ater n th s chapter
You can see some of the metadata that the comp er attaches to your code f you use the IL d sassemb er too (ILDASM), wh ch s nc uded w th the NET Framework SDK (You can find th s too n the
\Program F es\M crosoft SDKs\W ndows\v8 0a\b n\NETFX4 0 Too s fo der )
Using ILDASM
The fo ow ng examp e shows you how to use ILDASM to exam ne a s mp e app cat on
1. Start M crosoft V sua Stud o 2012 and create a new CLR Conso e App cat on project named
Hello
2. Add a new managed c ass to the app cat on
ref class Hello
{
public:
static void SayHello()
{
Console::WriteLine("Hello, world");
}
};
The c ass doesnt rea y have to do anyth ng part cu ar; t s s mp y here so that you can d sassemb e t to ook at the metadata
3. Bu d the app cat on to generate the executab e
4. Run ILDASM To do so, on the Too s menu, c ck V sua Stud o Command Prompt, and then
6. Were nterested n the managed type Hello, wh ch s nd cated by the b ue component sym-
bo C ck the p us s gn (+) to expand the tree for Hello and d sp ay the deta s of the c ass, as
dep cted n the fo ow ng screen shot
The type has three entr es the deta s of the c ass, and the entr es for two methods, wh ch are
the SayHello method you added and the defau t constructor prov ded by the comp er
7. Doub e-c ck the red tr ang e to br ng up the c ass nformat on
The defin t on of the managed c asswh ch extends System::Object s marked as private auto
ansi These keywords represent tems of metadata that have been added by the comp er to descr be
the c ass You can open the other methods n th s c ass to see what metadata s attached to them
You can nqu re about attr butes at run t me by us ng reflect on, wh ch s a feature by wh ch programmers can obta n nformat on about the objects they are us ng, such as what c ass the objects beong to, what methods the objects support, and what metadata s attached to them Us ng attr butes
n code s very powerfu because t g ves you a way to extend the programm ng anguage, ntroducng new propert es for your c asses that dont ex st n the base anguage
Later n the chapter, you see how to create custom attr butes and how to use code to ook at the
attr butes attached to c asses
ng examp e
[assembly:AssemblyVersionAttribute("1.1.105.3")];
DLLs in Windows
W ndows executab e code can be packaged n two forms as an executab e, or as a DLL DLLs
conta n executab e code but cant run on the r own A DLL conta ns funct ons or c asses used by
other code n a process It s oaded at run t me
There are both advantages and d sadvantages to us ng DLLs Here are some advantages
DLLs can be oaded and un oaded on demand, so app cat ons can contro the r memory
use
They can be shared by more than one process, so they are a good way to prov de shared
funct ona ty such as pr nter dr vers
Us ng DLLs means that t s poss b e to upgrade or fix part of an app cat on w thout havng to red str bute or re nsta everyth ng
There s a so one major drawback to DLLs n the trad t ona W ndows wor d an app cat on
m ght use the wrong vers on of a DLL When an app cat on wants to oad a DLL, t ooks a ong
the path for a fi e w th the r ght name and then oads the first one t finds So, f a user has
changed the order of d rector es on the r pathor f the path has been changed by nsta ng
or remov ng an app cat onthe app cat on m ght find another vers on of the DLL fi e before
the correct one Th s means that ocat ng the r ght DLL s dependent on the nd v dua computer setup, mak ng t hard to d agnose and fix
However, us ng the wrong vers on of a DLL snt a prob em for NET programmers, because
assemb esthe fundamenta bu d ng b ocks of NET app cat onshave vers on nformat on
bu t n, and t s poss b e to spec fy n the code exact y what vers ons of an assemb y are acceptab e If code does end up runn ng on a computer w th the wrong vers on of an assemb y,
the resu t w be a prec se and repeatab e error message rather than odd behav or
In the NET wor d, DLLs prov de one way to package up assemb es If an assemb y conta ns a
standard entry po nt such as main or WinMain, t s bu t as an executab e w th an exe extens on and can be executed from the command ne If the assemb y doesnt conta n an entry
po nt, t s bu t as a brary assemb y w th a d extens on A brary assemb y has no entry po nt
to beg n execut on but conta ns types that can be referenced from other assemb es
Th s exerc se shows you how to use a standard attr bute as we as how to create and use a DLL
Imag ne that you have a c ass that d dnt use propert es but, nstead, had an o d-fash oned exp c t
getter funct on You dec de to add propert es and want to nform deve opers that they shou d not be
us ng the o d getter funct on
1. Create a new CLR Conso e app cat on named UseAttributes
2. You create DLLs by us ng a C ass L brary project In So ut on Exp orer, r ght-c ck the so ut on
name On the shortcut menu that appears, po nt to Add, and then c ck New Project
3. When the Add New Project d a og box appears, se ect C ass L brary, ca the project MyDll,
and then c ck OK
The MyD h fi e opens n the ed tor
4. Ed t the c ass defin t on so that t ooks ke th s
namespace MyDll {
public ref class TestClass
{
int val;
public:
TestClass(int n) : val(n) { }
int getVal() { return val; }
property int Val {
int get() { return val; }
}
};
}
You can see that n add t on to the c ass hav ng a getter funct on, t now a so has a property
that does the same job
5. You dont want to remove the getter funct on because that m ght break ex st ng c ent code,
The Obsolete attr bute a erts the comp er that th s funct on shou dnt be used, and the message shou d be used to nform deve opers why and what to do nstead The second argument
d rects the comp er as to whether to treat use of th s funct on as an error or to on y ssue a
warn ng
6. Bu d the app cat on to ensure that you have no cod ng errors
7. To use the DLL from the conso e app cat on, you must add a reference to the conso e project
Open the project propert es d a og box for the UseAttr butes project by r ght-c ck ng the
project name (not the so ut on name!) and then, on the shortcut menu, c ck Propert es In the
d a og box, c ck Common Propert es, and then, n the pane on the eft, c ck Framework And
References
8. C ck the Add New Reference button to open the Add Reference d a og box In the pane on
the eft, c ck the So ut on entry Do ng so shows a the projects n the current so ut on You
shou d see MyD sted n the center pane se ect the check box adjacent to t, and then c ck
OK tw ce to d sm ss the d a og boxes If you expand the Externa Dependenc es entry under
the UseAttr butes project, you shou d see that t now d sp ays an entry for MyD
9. Open the UseAttr butes cpp source fi e and add a using d rect ve for the MyDll namespace
using namespace MyDll;
You cou d a so try chang ng the second argument to the Obsolete attr bute to true, rebu d the
ent re so ut on by se ect ng Rebu d So ut on from the Bu d menu, and check that use of the obso ete
funct on s now treated as an error
Note When you use the Build command, Visual Studio only recompiles those files that
have changed since the last build. Using Rebuild causes Visual Studio to rebuild the entire
project. This can be useful when youve made significant changes.
If you want to spec fy more than one target, you can comb ne two or more members together
w th the b tw se OR operator ( ), as you see n the next exerc se As you m ght expect, an attr bute
w thout AttributeUsage can be app ed to any code e ement
Th s attr bute has one pos t ona parameter and one named parameter ca ed type Pos t ona
parameters a ways appear before named parameters, are spec fied n a fixed order, and are passed to
the c ass constructor Named parameters are mp emented as propert es n the attr bute c ass
A ways add Attr bute to the c ass name for an attr bute (for examp e, ca a c ass
DocumentationAttribute rather than Documentation)
Prov de a read/wr te property for each named argument Be sure the name of the property
d ffers n case from that of the argument (for examp e, for an argument ca ed type, prov de a
property ca ed Type)
The custom attr bute needs to be created as a DLL so that t can be used n other projects
2. Open the CustomAttr butes h header fi e and ed t the ske eton c ass as fo ows
namespace CustomAttributes
{
[AttributeUsageAttribute(AttributeTargets::Method |
AttributeTargets::Property)]
public ref class DocumentationAttribute : Attribute
{
};
}
Our c ass s ca ed DocumentationAttribute and nher ts from System::Attribute The name fo ows the convent on of hav ng the c ass name for an attr bute end w th Attr bute The c ass
s tagged w th an AttributeUsage attr bute that m ts ts use to c ass methods and propert es
Note how you can use more than one member of the AttributeTargets enumerat on by comb n ng them w th the b tw se OR operator
3. The attr bute w
nc ude three p eces of data the documentat on text (wh ch w be a pos t ona parameter), and author and date str ngs (wh ch w be opt ona and thus mp emented
as named parameters) Add the dec arat ons for the three members to the c ass
namespace CustomAttributes
{
[AttributeUsageAttribute(AttributeTargets::Method |
AttributeTargets::Property)]
public ref class DocumentationAttribute : Attribute
{
String ^text;
// documentation text
String ^author;
// optional author field
String ^date;
// optional date field
};
}
The constructor takes a str ng as ts on y argument, saved away as the documentat on text
5. Add a read-on y property so that users can retr eve the text at run t me
// Read-only property to return the text
property String^ Text {
String^ get() { return text; }
}
Choose the names for the propert es carefu y because these are go ng to be used n c ent
code when us ng the attr bute
7. Bu d the app cat on to check that you havent made any errors
8. Add some code that w
9. Add an externa reference to the CustomAttr butes DLL, just as you d d n steps 7 and 8 of the
11. Define a managed c ass that uses the new custom attr bute, as demonstrated here
// A class to test the attribute
ref class TestAtts
{
int val;
public:
[DocumentationAttribute(
"The TestAtts class constructor takes an integer",
Author="julian", Date="10/10/01")]
TestAtts(int v)
{
val = v;
}
[DocumentationAttribute(
"The read-only Value property returns the value of"
" the int class member", Author="julian")]
property int Value
{
int get() { return val; }
}
};
The Documentation attr bute has been attached to the two members of th s c ass The constructor uses a three poss b e parameters, whereas the property uses on y the text and the
Author named parameter
Note Remember that you can split a string literal over two lines, and as long as
there is nothing between the closing and opening double quotation marks except
white space characters, the preprocessor will concatenate them for you.
12. Bu d the app cat on to ensure that t comp es c ean y
You can now use ILDASM to see how the attr bute data s he d n the c ass
13. Run ILDASM, as descr bed ear er, and open the TestAtts exe fi e
14. C ck the p us s gn (+) next to the b ue component symbo abe ed TestAtts and then doub e-
You can see how the code creates a DocumentationAttribute object, wh ch then forms part of
the TestAtts object You can access th s attr bute object from code (You see how to do th s
n the next sect on )
15. Before eav ng th s exerc se, try add ng the Documentation attr bute to the c ass, ke th s
[DocumentationAttribute("The TestAtts class", Author="julian")]
ref class TestAtts
{
...
}
Reflection
Query ng attr bute data s on y one aspect of reflection, a powerfu feature supported by many
anguages that have a runt me, such as C++/CLI, C#, and Java Reflect on s ma n y used for
three th ngs
The first, a so ca ed introspection, s to find nformat on about a type For examp e, you can
find out what members a type has, what ts base c ass s, and what nterfaces t mp ements You
w see th s n act on short y, when you use t to find out the attr butes attached to an object
The second use of reflect on s to create objects dynam ca y Th s can be usefu when you
dont know the exact type you want unt run t me For examp e, you cou d mag ne a p ug- n
mechan sm that oads a DLL at runt me, uses ntrospect on to see what types the DLL defines,
and then ets the user choose what to create
The th rd use s dynam c nvocat on, wh ch means execut ng funct ons and access ng propert es on an object dynam ca y at run t me Youd typ ca y do th s on an object youve created
dynam ca y
3. You need to create a Type object to use reflect on to find out about custom attr butes, so add
You obta n a Type object by us ng the GetType method that every NET type nher ts from
System::Object
4. You can check whether there are any custom attr butes on a c ass by us ng the GetCustom
We know that the c ass doesnt have any custom attr butes, so youd expect a count of 0 Note
the second Boo ean argument, wh ch spec fies that we want to nc ude any attr butes nher ted
from base c asses
5. Bu d and run the app cat on and check the output
6. To run the conso e app cat on, you w
7. The attr butes are actua y on the c ass members, not on the c ass tse f, so get a st of the
Ca ng GetMembers on the Type object returns an array of MemberInfo objects that descr be
the members Runn ng th s code on the TestAtts c ass nforms you that there are seven
members
Note The seven members are the constructor, the private data value, the property get method, and four methods inherited from the Object base class (Equals,
GetHashCode, GetType, and ToString).
8. Loop over the st of c ass members and get the custom attr butes for each one
for each (MemberInfo ^m in mi)
{
array<Object^> ^atts = m->GetCustomAttributes(true);
if (atts->Length > 0)
{
Console::WriteLine("Attributes for member {0}:", m->Name);
for each(Object ^att in atts)
{
Console::WriteLine(" attribute is {0}", att->ToString());
}
}
}
The outer oop cons ders each member n turn and ca s GetCustomAttributes on the Member
Info object to get a st of attr bute objects If there are any attr bute objects for th s member,
we pr nt them out
9. There are severa ways to figure out whether a member has the Documentation custom at-
tr bute, and the fo ow ng code shows one of them Mod fy the code for the nner oop n the
prev ous step so that t ooks ke th s
for each (Object ^att in atts)
{
Console::WriteLine(" attribute is {0}", att->ToString());
DocumentationAttribute ^da =
dynamic_cast<DocumentationAttribute^>(att);
if (da != nullptr)
{
Console::WriteLine("Doc attribute: {0}", da->Text);
}
}
The oop first uses dynamic cast to cast the current attr bute as a DocumentationAttribute hand e If that returns a non-nu va ue, you know that the cast worked, and so you can
retr eve the Text
10. Bu d and run the app cat on
You shou d see conso e output s m ar to that shown n the screen shot that fo ows, w th a stng of the attr butes present on c ass members and a show ng of documentat on text va ues
Quick reference
To
Do this
CHAPTER 24
be ab e to
Descr be how you can use Component Object Mode (COM) objects from NET projects
though the types prov ded n the M crosoft NET Framework are suffic ent for the vast majorty of app cat ons, somet mes you need to nteract w th ex st ng components, part cu ar y
COM components and Act veX contro s Th s chapter shows you how the wor ds of NET and COM
can nteroperate, mak ng t poss b e for you to take advantage of the best use of new and ex st ng
techno og es
Many peop e assumed that COM was dead when NET arr ved on the scene, and t s unden ab e
that NET prov des a better so ut on for creat ng a ot of component-based so ut ons If you program
n C++, though, t s st worth know ng about COM for two ma n reasons
F rst, there s a ot of COM code out there, n the form of Act veX contro s and ower- eve components, wh ch s not go ng to go away In fact, there are st some features of W ndows that arent
wrapped by NET for wh ch you need to use COM to access
The second, and perhaps more nterest ng reason, s that the W ndows RT APIs are COM based If
you want to get the max mum performance out of W ndows RT code (for examp e, f youre wr t ng
games n C++), you want to use COM
Note This chapter assumes that you know what COM objects are and something about
how to use them outside the .NET world. If terms such as GUID, HRESULT, IUnknown,
IDispatch, and type library dont mean anything to you, you should learn more about COM
before proceeding with this chapter.
475
.NET
Wrapper c asses are needed to br dge these d fferences so a COM object can appear as a NET
object, and v ce versa
Note Ive created a simple COM object for use in this exercise called TempConverter. It
implements simple temperature conversion functionality between Fahrenheit and Celsius.
Youll find the source and executable for the TempConverter project, plus a ReadMe.txt file
with directions for installing it, in this books sample files. Be sure TempConverter is installed
before starting this exercise.
1. Start V sua Stud o 2012 and create a new CLR Conso e App cat on project named ComWrapper
2. On the Project menu, c ck ComWrapper Propert es to open the Project Propert es d a og box
Se ect Common Propert es, and then, n the pane on the eft, c ck Frameworks And References,
and then c ck the Add New Reference button
3. In the Add Reference d a og box that opens, n the pane on the eft, choose the COM entry
It m ght take a few seconds to popu ate the st box w th deta s of the COM components
reg stered on your system
4. Browse the st to find the entry for the TempConverterLib component C ck to the eft of th s
5. You w
see that a new entry for TempConverterLib has been added to the projects st of
references
6. Open W ndows Exp orer and ook n the projects Interop d rectory You w
see that t conta ns a fi e ca ed Interop TempConverterL b 1 0 d , wh ch conta ns the RCW assemb y These
fi es are a ways named Interop XXX YYY d , where XXX and YYY are the name and vers on of
the COM component to wh ch the RCW refers
7. Open the IL d sassemb er too (ISDASM) and use t to exam ne Interop TempConverter 1 0 d
The sh e d- ke symbo w th the red top represents a namespace, so the namespace you need
to mport s TempConverterLib You can see that the assemb y conta ns three types Converter
and IConverter represent the or g na COM co-c ass and nterface defin t ons, respect ve y;
the r symbo s marked w th an I (a cap ta ) to show that they are nterfaces ConverterClass
s a rea type, so ts symbo doesnt conta n the I The RCW s produced by the t b mp too
8. To deduce the name of the wrapper c ass w thout us ng ILDASM, you take the name of the
9. Add a using d rect ve to your code to make t eas er to reference the RCW
using namespace TempConverterLib;
10. Add code to create a wrapper object, and use t to ca methods on the COM object, as shown
n the fo ow ng
int main(array<String^>^ args)
{
Console::WriteLine("COM Interop Sample");
// Create a COM object
ConverterClass ^conv = gcnew ConverterClass();
// Call a conversion method and print the result
double d = conv->ConvertC2F(27.0);
Console::WriteLine("27C is {0}F", d);
return 0;
}
Observe how the wrapper s created just ke any other managed object, and methods are
ca ed on t n exact y the same way as norma Theres no way to determ ne from th s code
that youre us ng a COM object, and the wrapper performs a the fet me management for
you
11. Bu d and run the app cat on, check ng that the output s what you expect
Th s code m ght return two error HRESULTs The first, E POINTER, occurs f the po nter to the resu t
var ab e s nu , wh ch wont happen when ca ed by the RCW The second, E INVALIDARG, occurs f an
nva d temperature s passed These are converted to except ons by the RCW, and as usua , you need
to catch them to prevent your app cat on from term nat ng Heres what you see on the conso e f
you pass an nva d temperature
480Microsoft Visual C++/CLI Step by Step
You can hand e th s by add ng a try/catch b ock to the code n the main funct on
try
{
double d = conv->ConvertC2F(-280.0);
Console::WriteLine("-280C is {0}F", d);
}
catch(Exception ^ex)
{
Console::WriteLine("Exception from COM object: {0}", ex->Message);
}
Aga n, bu d and run the app cat on and check that the output s correct
ter23, Attr butes and reflect on, for more deta s on the Type c ass and ts uses )
// Get a type representing the COM object
Guid g = Guid("75F3EDC5-AA71-437A-ACB6-F885C29E50F7");
Type ^t = Type::GetTypeFromCLSID(g);
if (t == nullptr)
{
Console::WriteLine("Error getting type for TConverter");
return -1;
}
Console::WriteLine("Got type for TConverter");
The GetTypeFromCLSID stat c method takes a COM c ass ID (CLSID) as a Guid object and
creates a Type object to represent the co-c ass If there s a prob em creat ng the Type object
because the CLSID cant be found or because of some other reg stry-re ated prob em, a nu
s returned Over oads of th s funct on et you spec fy that an except on be thrown nstead of
return ng a nu , f that su ts your code better
You can find the CLSID of a component by exam n ng the d fi e that was used when creatng t
3. Use the System::Activator c ass to create the COM object for you, as demonstrated here
// Use System::Activator to create an instance
Object ^obj = Activator::CreateInstance(t);
The Activator c ass creates nstances of oca or remote objects for you The reference returned
s a genera object reference; you dont need to cast t to any spec fic type because th s w be
taken care of for you ater
4. Bu d the parameter st before you ca a convers on method on the object Th s takes the
The CCW exposes a the nterfaces expected by c ents us ng COM, such as IUnknown and
IDispatch, and t ets the c ent code manage ts fet me n the norma COM manner
Installing assemblies
Assemb es are typ ca y nsta ed n one of two p aces Pr vate assemb es, wh ch are ntended
for use by a s ng e app cat on, can be p aced n the d rectory where the executab e res des
or any d rectory d rect y underneath Shared assemb es are nsta ed nto the G oba Assemb y Cache (GAC), wh ch s a per-computer repos tory for assemb es that need to be shared
You dont manua y copy assemb y fi es nto the GAC; you use the too s prov ded by the NET
Framework for manag ng the cache (such as gacut exe)
Assemb es must res de n one of these two ocat ons because they are where the CLR ooks
for them when t needs to oad them at run t me
Quick reference
To
Do this
Create a CCW.
Index
Symbols
+ (add t on operator), 30
& (ampersand character), 175
& (AND operator), 296
&& (AND operator), 31
= (ass gnment operator), 26
* (aster sk) symbo , 438
^ (caret) symbo , 391
~ (comp ement operator), 32
%d descr ptor, 422
/ (d v s on operator), 30
. (dot operator), 20
:: (doub e co on syntax), 79
= (equa s gn), 236, 254
# nc ude d rect ve, 439
# nc ude statements, 107
nt8 type, 24
nt16 type, 24
nt32 type, 24
nt64 type, 24
<< ( eft sh ft operator), 32
<= ( ess than or equa to) cond t on, 199
% (modu us operator), 30
* (mu t p cat on operator), 30
! (NOT operator), 31
= operator, 252, 254
> operator, 83
+ operator, 252
+= operator, 251, 254
> (po nter operator), 28
#pragma once d rect ve, 125
#pragma once ne, 240
>> (r ght sh ft operator), 32
:: (scope reso ut on operator), 269
[ ] (square brackets), 267
(subtract on operator), 30
A
Abs funct on, 169
Abstract attr bute, 469
abstract c asses
and sea ed c asses, 137
overv ew, 130 131
Account c ass, 14
n bank examp e, 238 240
AddAccount method, 240
Add funct on, 221
add t on operator (+), 30
Add method
n bank examp e, 240 241
Add New tem d a og box, 107
Add New Reference button, 461
add OnF rstEvent method, 256
addresses, WCF, 355
Add Serv ce d a og box, 364
AddServ ceEndpo nt, 363
ADO.NET
assemb es, 336
connected app cat on, creat ng
connect ng to database, 337 341
creat ng and execut ng command, 340 341
execut ng command that mod fies data, 341 342
execut ng quer es and process ng resu ts, 342
343
overv ew, 336 337
data prov ders, 334 335
d sconnected app cat on, creat ng, 344 345
d sconnected operat on us ng DataSet, 345 350
namespaces, 335
487
Age property
overv ew, 334 336
qu ck reference, 350, 368
Age property, 232
aggregate n t a zer, 202
a gor thms, 226
A Apps charm, 378
ampersand character (&), 175
AND operator (&), 296
AND operator (&&), 31
An ma c ass, 16
Ans C ass attr bute, 469
AP (app cat on programm ng nterface),
W ndows, 265
AppBarButton sty e, 427
app bars
AppBar contro , 383
n ca cu ator examp e, 425 428
AppendA L nes method, 292
AppendA Text method, 292
AppendCh d method, 324, 326
AppendText method, 292, 293
App.g.cpp, 380
App.g.h, 380
app cat on programm ng nterface (AP ),
W ndows, 265
App cat on U tab, 412
ArgumentExcept on, 222, 232, 239
Ar thmet cButtons C ck method, 404, 406
Ar thmet cExcept on, 184
ar thmet c operators, 30 31
over oad ng, 161 162
ar ty, 161
array keyword, 207
Array::Reverse method, 217
arrays
managed arrays
and reference types, 208 210
n t a z ng, 208
mu t d mens ona , 211
overv ew, 207 208
us ng for each oop w th, 210 211
nat ve
dynam c a ocat on of, 203 205
n t a z ng, 202
mu t d mens ona , 202 203
overv ew, 197 199
pass ng to funct ons, 200 202
overv ew, 28
System::Array c ass
bas c operat ons us ng, 213 215
488Index
automat c ayout, 449
Average funct on, 53
B
back ng var ab e, 233
Ba ance property, 241
BankAccount c ass, 123, 124, 130, 132, 136
bank examp e
add ng Account c ass, 238 239
Bank c ass
add ng accounts to, 240 243
mp ement ng, 236 238
overv ew, 236
base addresses, 355
BaseButtons C ck method, 418
base c asses, 126 129
BaseStream property, 298, 302, 318
BaseType property, 468
base var ab e, 419
Bas cHttpB nd ng, 355, 358
behav or of W ndows Store apps, 373
behav ors, WCF, 358 359
Berke ey Sockets protoco , 275
BestF tMapp ng fie d, 447
b nary /O
B naryReader c ass, 299 304
B naryWr ter c ass, 298
overv ew, 298
b nary operator, 162
B naryReader c ass, 274, 282, 299 303
B narySearch method, 212
B naryWr ter c ass, 274, 282, 298
b nd ng, WCF, 355
b tw se operators, 32 33
b ock ng, 283
Boo ean type, 271
Boo ean va ue type, 145
boo type, 24
Border contro , 383
BorderTh ckness property, 399
BottomAppBar e ement, 428
box ng 443
unbox ng, 443 444
box ng process, 171
break keyword, 73
breakpo nts, 47
BufferedStream c ass, 282
buffer overrun, 200
C
Cached F e Updater contract, W ndows 8, 429
ca cu ator examp e
add ng t e, 412 415
app bars, 425 428
ar thmet c buttons, 403 404
gett ng number from button, 404 405, 407 408
hand ng d fferent number bases
add ng buttons for, 417 418
chang ng base, 418 421
convert ng str ng n d sp ay, 421 425
hand ng number nput, 401 402
ay ng out number buttons, 398 401
overv ew, 397 398
perform ng ca cu at ons, 408 409
remember ng operat ons, 406
shar ng n
contracts and charms, 428 429
DataPackage c ass, 430
hand ng requests, 431 432
mp ement ng, 429 430
overv ew, 428
test ng, 410 412
Ca endar Ass stant app cat on, 61
Ca ngConvent on fie d, 447, 448
ca ng funct ons, 45 47
Ca Me method, 261
CanDeb t method, 123, 133, 134
Canvas contro , 388
Capac ty property, 220
caret (^) symbo , 391
cast ng process, 26
cast operator, overv ew, 33 34
catch b ock, 347
hand ng except ons us ng, 180 182, 189
C++/CL
defined, 3
He o Wor d examp e, 4
dent fiers n, overv ew, 5 6
keywords n, overv ew, 5 6
ma n funct on n, overv ew, 4 5
CCWs (COM Ca ab e Wrappers), 483
Index489
490Index
data contracts
Common Language Runt me (CLR), 20, 263 264,
336, 437, 454
Common Language Spec ficat on (CLS), 160, 298
Compare method, 222
CompareTo method, 218, 222
comp ng source fi es, 9 10
comp ement operator (~), 32
Component Object Mode (COM), 276. SeeCOM
concrete c asses, 130 131
Cond t ona Attr bute c ass, 458
Configurat onManager c ass, 339
ConformanceLeve property, 310
connected app cat on, ADO.NET
connect ng to database, 337 341
creat ng and execut ng command, 340 341
execut ng command that mod fies data, 341 342
execut ng quer es and process ng resu ts, 342
343
overv ew, 336 337
Connect on property, 340
Connect onStr ngSett ngs object, 339
connect onStr ngs sect on, 338
connect v ty, WCF, 353
Conso e ne, 4
Conso e::ReadL ne funct on, 44
Conso e::Wr te funct on, 44
constants
n c asses
c ass w de constants, 93 94
nstance constants, 94 95
overv ew, 93
overv ew, 28 29
const cast<> operator, 33
constructors
defin ng, 84 86
hand ng except ons for, 184 185
member n t a zat on sts, 86 87
for structures, 150
Conta nsKey method, 223
Conta ns method, 241
Conta nsVa ue method, 223
Content attr bute, 376
content contro s, 382
cont nue keyword, 73
contracts
n ca cu ator examp e, 428 429
WCF, 356 358
n W ndows Store apps, 374
contro s, n XAML, 382 383
Contro temp ates, 381
D
data adapter, 344
DataCo umn c ass, 344
DataContract c ass, 357
data contracts, 356
Index491
data hiding
data h d ng, 14
data members, c ass w de, 88 89
Data namespaces, 276 277
DataPackage c ass, n ca cu ator examp e, 430
data prov ders, ADO.NET, 334 335
DataRow c ass, 344
DataSet c ass, d sconnected operat on us ng,
344 350
DataTransferManager, 431
data types, for var ab es, 23 24
Date structure, 150, 152
DateT me c ass, 234
DbConnect on c ass, 336
DbDataAdapter c ass, 344
DbProv derFactory c ass, 346
DCOM (D str buted Component Object Mode ), 352
Debuggab eAttr bute c ass, 458
DebuggerH ddenAttr bute c ass, 458
DebuggerStepThroughAttr bute c ass, 458
debugg ng, stepp ng through app cat on, 47 51
Debug too bar, 49
dec arat ve U ayout, 381
dec ar ng var ab es
mu t p e, 26
overv ew, 25
decrement operators, over oad ng, 171 172
Defau tAttr bute, 395
defau t branch, 66
defau t va ues, for funct on prototypes, 40
de egate keyword, 247, 250
de egates
defin ng, 247
mp ement ng
ca ng non stat c member funct ons by us ng
de egates, 249
ca ng stat c member funct ons by us ng
de egates, 248 249
de egates that return resu t, 252 253
overv ew, 247
us ng mu t cast de egates, 249 252
overv ew, 245 246
purpose of, 246 247
De eteCommand, 345
de ete method
for arrays, 204
overv ew, 109
De ete method, 290, 291, 292, 293
Depth property, 307
deque type, STL/CLR, 226
der ved c asses, 129 130
492Index
destructors
overv ew, 105 106
us ng, 109 110
D agnost cs namespace, 274
D a og c ass, 265
D ct onary<K,V> c ass, 219
d rector es, gett ng nformat on about, 290 297
D rectory c ass, 274, 282
D rectory nfo c ass, 274, 282, 290 291
D rectoryName property, 293
D rectory property, 293
D sp ayDate funct on, 59
D spose method, 283, 287, 298 299, 308
D str buted Component Object Mode (DCOM), 352
d str buted systems, WCF, 352
D v deByZeroExcept on, 183
d v s on operator (/), 30
DLL (Dynam c L nk L brary), 192, 365 368, 444
D mport attr bute, 446
D mportAttr bute c ass, 447 448
DOB member, 151 152
Documentat on attr bute, 466
Documentat onAttr bute c ass, 464, 472
DocumentE ement property, 323
DocumentFragment node type, 309
Document node type, 309
Document Object Mode (DOM), 307
DocumentType node type, 309
DocumentType property, 323
do keyword, 72
DOM (Document Object Mode ), 307
dot operator (.), 20
doub e co on syntax (::), 79
Doub e type, 24, 271
Doub e va ue type, 144
do wh e oops, overv ew, 71 73
DtdProcess ng property, 310
dup ex operat on, 358
dynam c a ocat on, of arrays, 203 205
dynam c cast, 170, 444
dynam c cast<> operator, 33
dynam c nvocat on, 467
Dynam c L nk L brary (DLL, 192, 444
E
for each oop
us ng w th arrays, 210 211
EarnPo ntsOnAmount funct on, 97
files
EF (Ent ty Framework), 276
E NVAL DARG error, 480
E ement node type, 309
e ements n arrays, copy ng, 215
Enab eB naryButtons method, 420
Enab eDec ma Buttons method, 420
Enab eHexButtons method, 420
encapsu at on, n object or ented programm ng,
14 15
Encod ng property, 307
EndE ement node type, 309
EndEnt ty node type, 309
EndPo ntAddress c ass, 362
endpo nts, WCF, 353 354
Ent tyC ent data prov der, 334
Ent ty Framework (EF), 276
Ent ty node type, 309
Ent tyReference node type, 309
EntryPo nt fie d, 447 448
EnumerateD rector es method, 290 291
EnumerateF es method, 290 291
EnumerateF eSystemEntr es method, 290 291
enumerat ons
creat ng, 153 154
memory usage, 156
us ng n programs, 156
enumerators, us ng w th arrays, 218 219
EOF property, 307
E PO NTER eror, 480
Equa sButton C ck method, 407, 425
Equa s funct on, over oad ng, 169 171
equa s gn (=), 236
Equa s method, 74, 471
errNo fie d, 190
error hand ng, us ng COM components from
.NET, 480 481
Error L st w ndow, 10
errors, n propert es, 232
EventArgs object, 260
event hand ng, n XAML, 389
event keyword, 255
events
event rece ver, 256 258
event source c ass, 254 256
overv ew, 253 254
qu ck reference, 262
standard, 259 261
System::EventHand er de egate and, 259 261
EvtRcv c ass, 257
EvtSrc c ass, 255
F
fa through, us ng n sw tch statement, 67 68
fau t contracts, 356
F e dOffsetAttr bute c ass, 449
F FO (first n, first out), 226
F eAccess enumerat on, 286
F eAttr butes c ass, 296
F e c ass, 274, 282, 288
F e nfo c ass, 274, 282
F eMode enumerat on, 286
F e P cker contract, W ndows 8, 429
fi es. See alsob nary /O; See alsotext /O
gett ng nformat on about, 290 297
qu ck reference, 303 304
Index493
FileShare enumeration
F eShare enumerat on, 286
F eStream c ass, 274, 282, 286 287
fi e structure, for W ndows Store apps, 379 380
F eSystem nfo c ass, 274, 282
F eSystemWatcher c ass, 274, 282
F Buffer method, 299
fina Amount var ab e, 50
fina zers
overv ew, 106
us ng, 108 109
fina y b ock, 347
hand ng except ons us ng, 188
F ndA method, 212
F ndLast method, 212
F nd method, 212
F rstCh d property, 323, 326
F rstEventHand er de egate, 255
first n, first out (F FO), 226
F agsAttr bute, 395
F agsAttr bute c ass, 458
F pV ew contro , 384
float ng po nt types, 272
float ng po nt va ues, 169
float type, 24
flow contro statements
f statement
mu t way tests, 62 64
nested tests, 64 65
one way tests, 57 61
overv ew, 57
two way tests, 61 62
oop statements
do wh e oops, 71 73
for oops, 70 71
overv ew, 68
uncond t ona jumps n, 73 74
wh e oops, 68 70
sw tch statement
overv ew, 65 67
us ng fa through n, 67 68
F ushAsync method, 283
F ush method, 283, 298, 318
FontS ze property, 399
for each oop, 68
ForEach method, 212
Foreground property, 403
for oops, overv ew, 70 71
Format member, 154
Formatt ng property, 318, 320
forms, 370
494Index
G
GAC (G oba Assemb y Cache), 484
garbage co ector, 103 104
GCHand e::A oc method, 438
GCHand e type, and unmanaged code, 438 441
gcnew operator, 27, 28, 110, 143, 147, 208
gcroot var ab e, 440
GD 32.d , 445
generat ons, 104
gener c keyword, 206, 392
gener cs, n W ndows RT, 392
gener c types
and temp ates
overv ew, 224
STL/CLR brary, 224 227
overv ew, 205 206
Geometry.cpp fi e, 117
GetAccountNumber funct on, 82
GetAttr bute method, 308
GetAttr butes method, 292, 296
GetConstructor method, 468
GetConstructors method, 468
GetCreat onT me method, 290, 292
GetCurrentD rectory method, 290
GetCustomAttr bute method, 470
GetCustomAttr butes method, 470, 471
get date funct on, 229
GetDay funct on, 59
GetD rector es funct on, 297
GetD rector es method, 290, 291
GetD rectoryRoot method, 290
GetE ementBy d method, 324
GetE ementsByTagName method, 324
GetEnumerator method, 212, 218, 324, 326
GetEvent method, 468
GetEvents method, 468
GetF e d method, 468
GetF e ds method, 468
GetF es method, 290, 291
GetF eSystemEntr es method, 290
GetF eSystem nfos method, 291
get funct on, 161
GetHashCode method, 171, 471
Get nterestRate funct on, 87
Get nterfaceMap method, 468
Get nterface method, 468
Get nterfaces method, 468
Get nvocat onL st funct on, 253
GetLastAccessT me method, 290, 292
GetLastWr teT me method, 290, 292
GetLength method, 212, 214
GetLog ca Dr ves method, 290
GetLowerBound method, 212, 214
GetMember method, 468
GetMembers method, 468
get method, 234
GetMethod method, 468
GetMethods method, 468
GetMonth funct on, 59
GetNamespaceOfPrefix method, 326
GetNumberOfAccounts funct on, 90
GetParent method, 290
GetPrefixOfNamespace method, 326
GetPropert es method, 469
GetProperty method, 469
GetSystemPowerStatus funct on, 449, 450
getter, 231
GetTypeFromCLS D method, 481
GetType method, 469, 470, 471
GetUpperBound method, 213, 214
H
hand es
to objects, 118 119
overv ew, 27 28
hand ng except ons
catch b ock, 189
w th constructors, 184 185
Except on c ass propert es, 182 183
except on h erarchy, 184
fina y b ock, 188
try/catch b ocks, 180 182
hardware, and W ndows Store apps, 374
HasAttr butes property, 307
HasCh dNodes property, 323, 326
hashcode, 171
HashSet<T> c ass, 219, 273
HasSecur ty attr bute, 469
HasVa ue property, 307
header fi es, c asses n, 79 80
He o Wor d examp e, 4
h erarchy
for except ons, 184
for nher tance, 123 124
HttpGetEnab ed property, 364
HttpRequest c ass, 277
HttpResponse c ass, 277
HTTP transport, 354
I
Channe hand e, 362
Co ect on<T> nterface, 273
Comparab e nterface, 218
Comparer<T> nterface, 273
Connect onPo ntConta ner nterface, 477
Connect onPo nt nterface, 477
DE ( ntegrated deve opment env ronment), 11
Index495
identifiers, overview
dent fiers, overv ew, 5 6
D ct onary<K,V> nterface, 273
D spatchEx nterface, 477
D spatch nterface, 477
Enumerab e<T> nterface, 273
Enumerator nterface, 210
Enumerator<T> nterface, 273
EnumVAR ANT nterface, 477
Error nfo nterface, 477
f statement
mu t way tests, 62 64
nested tests, 64 65
one way tests, 57 61
overv ew, 57
two way tests, 61 62
gnoreComments property, 310
gnoreProcess ng nstruct ons property, 310
gnoreWh tespace property, 310
LDASM, 454 457
LDASM too , 264
L D sassemb er too , 264
L ( ntermed ate Language), 375
L st<T> nterface, 273
MathServ ce contract, 361
MetadataExchange contract, 363
mport attr bute, 469
mportNode method, 324
# nc ude d rect ve, 439
nc ude guard, 360
# nc ude statements, 79, 96
ncrement operators, over oad ng, 171 172
ndentat on property, 318
ndentChar property, 318
ndexed propert es
bank examp e
creat ng Account c ass propert es, 239 240
mp ement ng to retr eve accounts, 241 244
defined, 230
overv ew, 236
ndex ng, 207
ndexOfKey method, 223
ndexOf method, 213, 216
ndexOfVa ue method, 223
nher tance
abstract c asses, 130 131
and code reuse, 122
base c asses, 126 129
concrete c asses, 130 131
der ved c asses, 129 130
496Index
/O ( nput/output)
b nary /O, 298
B naryReader c ass, 299 303
B naryWr ter c ass, 298
text /O
F eStream c ass, 286 287
overv ew, 283
TextReader, 287 290
TextWr ter, 283 285
O namespace, 274
PC ( nter process commun cat on), 353
PC transport, 354
Prov deC ass nfo nterface, 477
ReadOn yCo ect on<T> nterface, 273
sAbstract property, 468
sArray property, 468
sByRef property, 468
sC ass property, 468
sEmptyE ement property, 307
Set<T> nterface, 273
sF xedS ze property, 212
s nterface property, 468
sNotPub c property, 468
sPub c property, 468
sReadOn y property, 212, 323, 326
sStartE ement method, 308
sSynchron zed property, 212
sVa ueType property, 468
tem property, 307, 323, 326
tems contro s, 382
terator, 225, 226
Unknown nterface, 477
J
J T (Just n T me) comp er, 264
Just n T me (J T) comp er, 264
K
Kerne 32.d , 445
KeyRoutedEventArgs, 389
KeyVa uePa r c ass, 223
keywords, overv ew, 5 6
L
LastAccessT me property, 291, 293
LastCh d property, 323, 326
main function
mp ement ng c ass, 96 97
test ng app cat on, 100 101
M
ma n funct on, 41, 248
overv ew, 4 5
ma n method, 108
Ma nPage c ass, 406
Ma nPage.g.cpp, 380
Ma nPage.g.h, 380
MakePurchase funct on, 80, 98
MakeRepayment funct on, 80
managed arrays
and reference types, 208 209
n t a z ng, 208
mu t d mens ona , 211
overv ew, 207
us ng for each oop w th, 210 211
managed code
vs. unmanaged code
GCHand e type, 438 441
m xed c asses, 437 438
overv ew, 437
Map type, 394
map type, STL/CLR, 226
MapV ew type, 394
Marg n property, 376
markup extens ons, 382
Marsha AsAttr bute c ass, 458
marsha ng, 356
Math::Abs funct on, 169
MathServ ceC ent c ass, 368
MaxCharacters nDocument property, 310
Max mumRowsOrCo ums attr bute, 387
MBCS (Mu t Byte Character Set), 405
MC ass object, 440
mc var ab e, 440
member funct ons, c ass w de, 90 91
member n t a zat on sts, n constructors, 86 87
MemoryStream c ass, 274, 282
memory usage, for enumerat ons, 156
MEPs (message exchange patterns), 357 358
MessageBox funct on, 445, 446
Message property, Except on c ass, 182
metadata
add ng to WCF serv ces, 363 365
and attr butes
overv ew, 453 454
us ng LDASM, 454 457
498Index
N
named parameters, 463
named p pes, 353
Name property, 291, 293, 307, 323, 326
Namespace property, 468
namespaces
ADO.NET, 335
.NET
Co ect ons nterfaces, 273 274
Co ect ons namespaces, 272 273
Data namespaces, 276 277
D agnost cs namespace, 274
O namespace, 274
Net namespaces, 275
object-oriented programming
overv ew, 268 269
Serv ceMode namespaces, 275
System namespace, 270 273
us ng n C++ app cat ons, 270 271
Web namespaces, 277 278
W ndows namespaces, 275
Xm namespaces, 276
Namespaces property, 318
NamespaceUR property, 307, 323
nam ng, of var ab es, 25 26
NaN (not a number), 272
nat ve arrays
dynam c a ocat on of, 203 205
n t a z ng, 202
mu t d mens ona , 202 203
overv ew, 197 199
pass ng to funct ons, 200 202
negat ve nfin ty, 272
nest ng
except ons, 185 188
f statements, 64 65
.NET
us ng COM components from
and RCWs, 476 477
creat ng RCWs, 477 480
hand ng errors, 480 481
ate b nd ng to COM objects, 481 482
overv ew, 476
us ng .NET components as COM
components, 483 485
.NET Framework
assemb es, 266
c ass brary, 265
CLR (Common Language Runt me), 263 264
CLS (Common Language Spec ficat on), 265
CTS (Common Type System), 264
metadata, 266 268
MS L (M crosoft ntermed ate Language), 264
namespaces
Co ect ons nterfaces, 273 274
Co ect ons namespaces, 272 273
Data namespaces, 276 277
D agnost cs namespace, 274
O namespace, 274
Net namespaces, 275
overv ew, 268 269
Serv ceMode namespaces, 275
System namespace, 270 273
us ng n C++ app cat ons, 270 271
Web namespaces, 277 278
O
Object L nk ng and Embedd ng (OLE), 370
object or ented programm ng
advantages of, 16 17
c asses n, 16
defined, 13 14
Index499
objects
encapsu at on n, 14 15
examp e of, 17 22
nher tance n, 15
objects n, 16
po ymorph sm n, 15 16
objects
and stack semant cs
creat ng objects w th, 111 113
overv ew, 116 118
copy constructors, 113 116
creat ng, 83 84
destructors
overv ew, 105 106
us ng, 109 110
fina zers
overv ew, 106
us ng, 108 109
hand es to, 118 119
fet mes of, 103 105
n object or ented programm ng, 16
re at onsh ps for
creat ng Loya tyScheme c ass, 95 96
creat ng Loya tyScheme objects, 97 100
mp ement ng Loya tyScheme c ass, 96 97
overv ew, 95 96
test ng examp e app cat on, 100 101
trad t ona C++ creat on and destruct on, 110
111
obj po nter, 444
Observer c ass, 261
Obso ete attr bute, 460
Obso eteAttr bute c ass, 458
ODBC data prov der, 334
O eDb data prov der, 334
OLE (Object L nk ng and Embedd ng), 370
one way messag ng, 358
OnNav gatedFrom funct on, 432
OnNav gatedTo funct on, 421, 432
op Add t on operator, 166
op AddressOf operator, 166
op B tw seAnd operator, 166
op B tw seOr operator, 166
op Comma operator, 166
op Decrement operator, 166
op D v s on operator, 166
Open method, 292 293
OpenRead method, 292 293
OpenText method, 292 293
OpenWr te method, 292 293
op Equa ty operator, 166
500Index
over oad ng funct ons, 53 55
overr d ng member funct ons, 131 136
OwnerDocument property, 324, 326
P
Package.appxman fest fi e, 379, 412
Page c ass, 377
Page e ement, 375
ParamArrayAttr bute c ass, 458
parameters
n funct on bod es, 42 43
n funct on prototypes, 39
names for, 39
ParentNode property, 324, 326
Parent property, 291
pars ng XML us ng, Xm ReaderSett ngs c ass,
310 314
part a c asses, 391
part a keyword, 392
pass ng structured data, 449 452
Path c ass, 274, 282
PeekChar method, 299
Peek method, 287
pf funct on po nter, 246
p nn ng po nters, 441 442
P/ nvoke (P atform nvoke)
ca ng funct ons n W n32 AP
D mportAttr bute c ass, 447 448
overv ew, 444 447
pass ng structured data, 449 452
P atform::Co ect ons namespace, 394
P atform nvoke (P/ nvoke). SeeP/ nvoke
P atform::Metadata namespace, 394
P atform namespaces, n W ndows RT, 394
P ay To contract, W ndows 8, 429
PNG (Portab e Network Graph cs) fi es, 379, 414
po nter operator ( >), 28
po nters
nter or po nters, 441
overv ew, 27 28
p nn ng po nters, 441 442
po ymorph sm
n object or ented programm ng, 15 16
pop back funct on, 225
Portab e Network Graph cs (PNG) fi es, 379, 414
pos t ona parameters, 463
pos t ve nfin ty, 272
post decrement, 171
ProviderName property
postfix ncrement operator express on, 31
post ncrement, 171
#pragma once d rect ve, 125
precedence, of operators, 34
precomp ed headers, 379
pre decrement, 171
predefined attr butes
Assemb y nfo.cpp fi e, 457 458
c asses for, 458 461
obta n ng attr bute data us ng, 469
overv ew, 457
prefix ncrement operator express on, 31
Prefix property, 308, 324, 326
pre ncrement, 171
PrependCh d method, 326
PreserveS g fie d, 448
PreserveWh tespace property, 324
Prev ousS b ng property, 323, 326
pr ntArea funct on, 236
Pr ntStatement funct on, 78
pr vate auto ans , 456
pr vate c ass, 136
pr vate keyword, 19
ProcessCh dNodes funct on, 330
processF e funct on, 297
Process ng nstruct on node type, 309
project ons, 390
Project Propert es d a og box, 338
projects, creat ng, 8 9
propert es
for custom attr butes, 463 464
for Except on c ass, 182 183
ndexed
bank examp e, 236 244
overv ew, 236
overv ew, 229 230
qu ck reference, 244
sca ar propert es
auto mp emented propert es, 233
errors n propert es, 232
nher tance and, 235
n nterfaces, 235 236
overv ew, 231 232
read on y and wr te on y propert es, 233 235
of va ue types, 145
Propert es property, 430
Propert es tab, 402
property keyword, 231
protected access, 136 137
Prov derName property, 339
Index501
Q
Queue<T> c ass, 219, 273
queue type, STL/CLR, 226
QuoteChar property, 318
R
Ra seOne funct on, 259
ra se OnF rstEvent method, 256
Ra seTwo funct on, 259
Rank property, 212, 213
rateFract on var ab e, 50
RC (Re ease Cand date) vers on, 7
RCWs (Runt me Ca ab e Wrappers)
creat ng, 477 480
overv ew, 476 477
Read7B tEncoded nt method, 299
ReadAsync method, 287, 308
ReadAttr buteVa ue method, 308
ReadB ockAsync method, 287
ReadB ock method, 287
ReadBoo ean method, 299
ReadByte method, 299
ReadBytes method, 299
ReadChar method, 299
ReadChars method, 299
ReadContentAsAsync method, 308
ReadContentAs nt method, 308
ReadContentAs method, 308
ReadContentAsStr ng method, 308
ReadDec ma method, 299
ReadDoub e method, 299
ReadE ementContentAs nt method, 308
ReadE ementContentAs method, 308
ReadE ementStr ng method, 308
ReadEndE ement method, 309
Read funct on, 313
Read nnerXm method, 308
Read nt16 method, 299
Read nt32 method, 299
Read nt64 method, 299
ReadL ne method, 287, 289
502Index
Remove funct on, 221
RemoveHand er funct on, 259
Remove method
n bank examp e, 240 241
man pu at ng nvocat on sts us ng, 250
remove OnF rstEvent method, 256
RemoveRange funct on, 221
Rep aceCh d method, 325, 327
Rep ace method, 292, 293
reserved words, 5
Reset funct on, 409
Reset method, 210
Res ze method, 213
resource d ct onar es, 381
restr ct ons, on operator over oad ng, 160
rethrow ng except ons, 185 188
return keyword, 4, 41
return type
for funct on bod es, 43 45
for funct on prototypes, 39 40
Reverse method, 213
r ghtOperand var ab e, 408
r ght sh ft operator (>>), 32
RM (Remote Method nvocat on), 352
Root property, 291
RoutedEventArgs c ass, 389
RowDefin t on e ement, 386
runn ng programs, 7, 11
Runt me Ca ab e Wrappers (RCWs). SeeRCWs
Runt meWrappedExcept on, 192
S
safe cast, 444
safe cast keyword, and except ons, 191 192
safe cast<> operator, 33
Save method, 325
Sav ngsAccount c ass, 15, 123, 126 127, 130
Sav ngsAccount.cpp project, 129
Sav ngsAccount header fi e, 129
SAX (S mp e AP for XML) AP , 307
SayHe o method, 456
SByte type, 271
SByte va ue type, 144
sca ar propert es
auto mp emented, 233
defined, 230
errors n, 232
nher tance and, 235
SetHtmlFormat method
n nterfaces, 235
read on y and wr te on y, 233 234
Schema c ass, 276
Schema nfo property, 308
Schemas property, 310, 324
scope
g oba scope, 51 53
oca scope, 51 53
scope reso ut on operator (::), 269
Scro V ewer contro , 384
Sea ed attr bute, 469
sea ed c asses
and abstract c asses, 137
overv ew, 137
Search contract, W ndows 8, 428
search ng, arrays, 216 217
SecondEventHand er de egate, 257
secur ty perm ss ons, 266
Seek method, 298, 302
SeekOr g n enumerat on, 302
seek po nter, 302
SEH (Structured Except on Hand ng), 178
Se ectCommand, 345
Se ectCommand property, 347
Se ected Components pane, 193
Se ectNodes method, 325, 327
Se ectS ng eNode method, 325, 327
sequent a ayout, 449
Ser a zab e attr bute, 469
Ser a zab eAttr bute c ass, 458
Ser a zat on c ass, 276
Serv ceContract attr bute, 356
serv ce contracts, 356
Serv ceMode namespaces, 275
serv ces
WCF, 352
access ng by us ng proxy, 365 368
add ng metadata to, 363 365
overv ew, 359 362
wr t ng serv ce c ent, 361 362
SetAttr butes method, 292
SetB tmap method, 430
SetCreat onT me method, 290, 292
SetCred tL m t funct on, 80
SetCurrentD rectory method, 291
SetCursorToArrow ne, 112
SetData method, 430
SetDataProv der method, 430
set date funct on, 229
SetHtm Format method, 430
Index503
SetInterestRate function
Set nterestRate funct on, 87
SetLastAccessT me method, 291 292
SetLastError fie d, 448
SetLastWr teT me method, 291 292
SetName funct on, 20
SetRtf method, 430
SetStorage tems method, 431
setter, 231
SetText method, 431
Sett ngs contract, W ndows 8, 429
Sett ngs property, 308, 318
set type, STL/CLR, 226
SetUr method, 431
SetVa ue method, 213, 214
Shape c ass, 235
Share contract, W ndows 8, 429
shar ng
n ca cu ator examp e
contracts and charms, 428 429
DataPackage c ass, 430
hand ng requests, 431 432
mp ement ng, 429 430
overv ew, 428
short c rcu t eva uat on, 32, 60
short type, 24
S gn ficantWh tespace node type, 309
S mp e AP for XML (SAX) AP , 307
S mp e Ma Transfer Protoco (SMTP), 277
S mp e Object Access Protoco (SOAP), 277, 306
s mp ex messag ng, 358
s ng e byte str ng type, 405
S ng e type, 271
S ng e va ue type, 144
s zeof operator, 201
Sk pAsync method, 309
Sk p method, 309
SMTP (S mp e Ma Transfer Protoco ), 277
SOAP (S mp e Object Access Protoco ), 277, 306
SortedL st<K,V> c ass, 273
overv ew, 219, 222 223
SortedSet<T> c ass, 273
sort ng, arrays, 217 218
Sort method, 213
Source property, Except on c ass, 182
Sq C ent data prov der, 334
Sq ServerCe data prov der, 334
square brackets [ ], 267
square funct on, 248
StackPane contro , 384
504Index
ThrowOnUnmappableCharacter field
swscanf s funct on, 404, 409
symbo c constant, 28
Synchron zed method, 283, 287
SyncRoot property, 212
syntax, for XAML, 381 382
System::App cat onExcept on c ass, 179
System::ArgumentExcept on c ass, 179
System::Ar thmet cExcept on c ass, 179
System::Array c ass
bas c operat ons us ng, 213 214
copy ng e ements, 215
overv ew, 212
search ng, 216 217
sort ng, 217 218
us ng enumerators w th, 218 219
System::Co ect on namespace, 218
System::Co ect ons::Gener c namespace, 219
System::Configurat on assemb y, 345
System::Data::Common namespace, 335
System::Data::Ent tyC ent namespace, 276, 335
System::Data::L nq namespace, 335
System::Data namespace, 335
System::Data::Odbc namespace, 276, 335
System::Data::O eDb namespace, 276, 335
System::Data::Orac eC ent namespace, 276, 335
System::Data::Serv ces namespace, 335
System::Data::Spat a namespace, 335
System::Data::Sq C ent namespace, 276, 335
System::Data::Sq Types namespace, 335
System::De egate c ass, 247
System::D agnost cs namespace, 458
System::D v deByZeroExcept on error, 177
System::Enum c ass, 153
System::EventHand er de egate, events and, 259 261
System::Except on c ass, 177, 179
System::GC::Co ect stat c method, 105
System:: ndexOutOfRangeExcept on c ass, 179
System:: nva dCastExcept on c ass, 179
System:: O namespace, 281 282
System::MemberAccessExcept on c ass, 179
System::Mu t castDe egate c ass, 247, 249
System namespace
bas c types, 271
float ng po nt types, 272
overv ew, 270 271
System::NotSupportedExcept on c ass, 179
System::Nu ReferenceExcept on c ass, 179
System::Object c ass, 169
System::OutOfMemoryExcept on c ass, 179
SYSTEM POWER STATUS structure, 449
T
TCP/ P transport, 354
TempConverterL b component, 478
TempConverter project, 478
temp ates, and gener c types
overv ew, 224
STL/CLR brary
concepts beh nd, 225 227
overv ew, 224 225
ternary operator, overv ew, 32 33
TestAtts c ass, 466, 471
test ng, ca cu ator examp e, 410 412
Test method, 193
text /O
F eStream c ass, 286 287
overv ew, 283
TextReader, 287 290
TextWr ter, 283 286
Text node type, 309
TextReader c ass, 274, 282, 287 290
TextWr ter c ass, 274, 283 285
throw ng except ons, 178 180
throw keyword, 177
ThrowOnUnmappab eCharacter fie d, 448
Index505
U
UC ass object, 440
U nt16 type, 271
U nt16 va ue type, 144
U nt32 type, 271
U nt32 va ue type, 144
U nt64 type, 271
U nt64 va ue type, 144
U ntPtr type, 271
U (user nterface)
brar es for W ndows app cat ons, 372
mode for W ndows Store apps, 374
U (user nterface) framework, 275
U nPtr va ue type, 145
UML (Un fied Mode ng Language), 123
unbox ng, 443 444
uncond t ona jumps, n oop statements, 73 74
Under y ngSystemType property, 468
Un codeC ass attr bute, 469
Un fied Mode ng Language (UML), 123
unmanaged code, 264
box ng, 443
nter or po nters, 441
p nn ng po nters, 441 442
unbox ng, 443 444
us ng P/ nvoke to ca funct ons n W n32 AP
D mportAttr bute c ass, 447 448
overv ew, 444 447
506Index
V
Va Hand er c ass, 317
Va date method, 325
Va dat onF ags property, 310
Va dat onType property, 310
va ue keyword, 20, 146, 161
Va ue property, 308, 324, 326
Va ueType property, 308
va ue types
and reference types
overv ew, 143 144
enumerat ons
creat ng, 153 154
memory usage, 156
us ng n programs, 156
propert es of, 145
purpose of, 144 145
structures
constructors for, 150
copy ng, 152 153
creat ng, 146 148
overv ew, 146
us ng w th n another, 150 152
vs. c asses, 149 150
var ab es
arrays, 28
ass gn ng va ues to, 26 27
constants, 28 29
data types for, 23 24
dec ar ng
mu t p e, 26
overv ew, 25
defined, 23
hand es, 27 28
nam ng of, 25 26
po nters, 27 28
Str ng c ass, 29 30
typedefs, 29
Var ab eS zedWrapGr d contro , 387
Vector terator c ass, 394
Vector type, 394
vector type, STL/CLR, 226
VectorV ew terator c ass, 394
VectorV ew type, 394
Veh c e c ass, 122
vers on ng, 266
V rtua z ngStackPane contro , 385
vo d keyword, 38
W
W3C DOM, 322
WCF (W ndows Commun cat on Foundat on)
addresses, 355
behav ors, 358 359
b nd ng, 355
connect v ty, 353
contracts, 356 358
defined, 275
d str buted systems, 352
endpo nts, 353 354
MEPs (message exchange patterns), 357 358
overv ew, 351
serv ces, 352
access ng by us ng proxy, 365 368
add ng metadata to, 363 365
overv ew, 359 362
wr t ng serv ce c ent, 361 362
wchar t* po nter, 405
wchar t type, 24
wcsto (W de Character Str ng To Long) funct on, 422
Web namespaces, 277 278
web serv ce, 277
Web Serv ce Defin t on Language (WSDL), 355
Web Serv ce Descr pt on Language (WSDL), 306
WeekDay c ass, 154
wh e oops, overv ew, 68 70
wh te space, 5
Wh tespace node type, 309
W de Character Str ng To Long (wcsto )
funct on, 422
w de str ng type, 405
W n32 AP , 369 370
ca ng funct ons us ng P/ nvoke
D mportAttr bute c ass, 447 448
overv ew, 444 447
pass ng structured data, 449 452
Windows::System namespaces
ma n features
app behav or, 373
contracts and charms, 374
hardware usage, 374
overv ew, 373
U mode , 374
W nRT AP s, 374
overv ew, 372 373
W ndows RT
c asses, 391 392
gener cs, 392
metadata, 390
overv ew, 389 390
P atform namespaces, 394 395
str ngs, 392 393
W ndows namespaces, 393
XAML
contro s, 382 383
defined, 380 381
event hand ng, 389
ayout contro s, 384 388
syntax, 381 382
W ndows::System namespaces, 394
W ndows::U namespaces, 394
W ndows::U ::XAML namespaces, 394
W ndows::Web namespaces, 394
W nRT (W ndows RT)
AP s, 374
c asses, 391 392
gener cs, 392
metadata, 390
overv ew, 389 390
P atform namespaces, 394
str ngs, 392 393
W ndows namespaces, 393
WPF (W ndows Presentat on Foundat on), 275
Wr te7B tEncoded nt method, 298
Wr teA L nes method, 292
Wr teA Text method, 292
Wr teAsync method, 283
Wr teAttr butes method, 318
Wr teAttr buteStr ng method, 318
Wr teBase64 method, 318
Wr teB nHex method, 318
Wr teCData method, 319
Wr teCharEnt ty method, 319
Wr teChars method, 319
Wr teComment method, 319
Wr teContentTo method, 325, 327
Wr teDocType method, 319
508Index
X
XAML (Extens b e App cat on Markup Language)
contro s, 382 383
defined, 380 381
event hand ng, 389
ayout contro s, 384 388
project fi es, 379
syntax, 381 382
Xam Type nfo.g.h, 380
Xm c ass, 276
Xm Dec arat on node type, 309
Xm Document c ass, 322
XML (eXtens b e Markup Language)
NET and
NET XML namespaces, 306
overv ew, 305 306
XML process ng c asses, 306 307
ZIndex property
pars ng us ng Xm Reader
creat ng Xm Readers, 309 310
hand ng attr butes, 314 315
overv ew, 307 309
ver fy ng we formed XML, 314
w th va dat on, 315 317
Xm ReaderSett ngs c ass, 310 314
qu ck reference, 332
wr t ng us ng Xm TextWr ter, 318 322
Xm Document c ass
overv ew, 322
W3C DOM and, 322
Xm Node c ass, 325 332
Xm Lang property, 308, 318
Xm namespaces, 276
Xm Node c ass, 325 332
Xm NodeType enumerat on, 309
Xm Reader c ass
pars ng XML us ng
creat ng Xm Readers, 309 310
hand ng attr butes, 314 315
overv ew, 307 309
ver fy ng we formed XML, 314
w th va dat on, 315 317
Xm ReaderSett ngs c ass, 310 314
Xm Reso ver property, 310
Xm Space property, 318
Xm TextReader c ass, 307
Xm TextWr ter c ass
creat ng object, 348
wr t ng XML us ng, 318 322
Xm Va dat ngReader c ass, 307
Xm Wr ter c ass, 138
x:Name attr bute, 381
XPath c ass, 276
Xs c ass, 276
XSL (Extens b e Sty esheet Language) processor, 276
XSLT (Extens b e Sty esheet Language
Transformat ons), 306
Z
Z ndex property, 388
Index509