You are on page 1of 542

Microsoft Visual C++/CLI

Step by Step

Julian Templeman

Pub shed w th the author zat on of M crosoft Corporat on by


ORe y Med a, Inc
1005 Gravenste n H ghway North
Sebastopo , Ca forn a 95472
Copyr ght 2013 by Ju an Temp eman
A r ghts reserved No part of the contents of th s book may be reproduced or transm tted n any form or by any
means w thout the wr tten perm ss on of the pub sher
ISBN 978-0-7356-7517-9
1 2 3 4 5 6 7 8 9 LSI 8 7 6 5 4 3
Pr nted and bound n the Un ted States of Amer ca
M crosoft Press books are ava ab e through bookse ers and d str butors wor dw de If you need support re ated
to th s book, ema M crosoft Press Book Support at msp nput@m crosoft com P ease te us what you th nk of
th s book at http://www.microsoft.com/learning/booksurvey
M crosoft and the trademarks sted at http://www.microsoft.com/about/legal/en/us/IntellectualProperty/
Trademarks/EN-US.aspx are trademarks of the M crosoft group of compan es A other marks are property of
the r respect ve owners
The examp e compan es, organ zat ons, products, doma n names, ema addresses, ogos, peop e, p aces, and
events dep cted here n are fict t ous No assoc at on w th any rea company, organ zat on, product, doma n name,
ema address, ogo, person, p ace, or event s ntended or shou d be nferred
Th s book expresses the authors v ews and op n ons The nformat on conta ned n th s book s prov ded w thout
any express, statutory, or mp ed warrant es Ne ther the authors, ORe y Med a, Inc , M crosoft Corporat on,
nor ts rese ers, or d str butors w be he d ab e for any damages caused or a eged to be caused e ther d rect y
or nd rect y by th s book
Acquisitions and Developmental Editor: Russe Jones
Production Editor: Kara Ebrah m
Technical Reviewer: Luca Regn co
Copyeditor: Octa Pub sh ng, Inc
Indexer: BIM Index ng and Proofread ng Serv ces
Cover Design: Tw st Creat ve Seatt e
Cover Composition: E e Vo ckhausen
Illustrator: Rebecca Demarest

I would like to dedicate this book to my wife, Jane, without


whose steadfast love and support none of this would be possible.
Jul an Templeman

Contents at a Glance
Introduction xxi
Part I

GETTING STARTED WITH C++ .NET

Chapter 1

Hello C++!

Chapter 2

Introducing object-oriented programming

13

Chapter 3

Variables and operators

23

Chapter 4

Using functions

37

Chapter 5

Decision and loop statements

57

Chapter 6

More about classes and objects

77

Chapter 7

Controlling object lifetimes

Chapter 8

Inheritance 121

Part II

MICROSOFT .NET PROGRAMMING BASICS

Chapter 9

Value types

143

Chapter 10

Operator overloading

159

Chapter 11

Exception handling

175

Chapter 12

Arrays and collections

197

Chapter 13

Properties 229

Chapter 14

Delegates and events

245

Chapter 15

The .NET Framework class library

263

Part III

USING THE .NET FRAMEWORK

Chapter 16

Working with files

281

Chapter 17

Reading and writing XML

305

Chapter 18

Using ADO.NET

333

Chapter 19

Writing a service by using Windows


Communication Foundation

351

Chapter 20

Introducing Windows Store apps

369

Chapter 21

More about Windows Store apps

397

103

Part IV

ADVANCED TOPICS

Chapter 22

Working with unmanaged code

437

Chapter 23

Attributes and reflection

453

Chapter 24

Living with COM

475

Index 487

vi

Contents at a Glance

Contents
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xxi

Part I

GETTING STARTED WITH C++ .NET

Chapter 1 Hello C++!

What s C++/CLI?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Your first C++/CLI app cat on. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

The main funct on. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

C++ keywords and dent fiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Creat ng an executab e app cat ontheory. . . . . . . . . . . . . . . . . . . . . . . . . .

Ed t ng the app cat on source fi es. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Comp ng the source fi es . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Runn ng and test ng the app cat on . . . . . . . . . . . . . . . . . . . . . . . . . . .

Creat ng an executab e app cat onpract ce

Creat ng a project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Ed t ng the C++ source code. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Bu d ng the executab e . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Execut ng the app cat on. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

11

Conc us on. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

11

Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

11

Chapter 2 Introducing object-oriented programming

13

What s object-or ented programm ng?. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

13

Features of object-or ented programm ng anguages. . . . . . . . . . . . . . . . .

14

Encapsu at on. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

14

Inher tance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

15

Po ymorph sm. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

15

C asses and objects. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

16


vii

Benefits to the deve opment fe cyc e. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

16

A s mp e examp e. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

17

Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

22

Chapter 3 Variables and operators

23

What s a var ab e? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

23

The fundamenta data types. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

23

Dec ar ng a var ab e. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

25

Var ab e nam ng. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

25

Dec ar ng mu t p e var ab es. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

26

Ass gn ng va ues to var ab es . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

26

Hand es and po nters. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

27

Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

28

Constants. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

28

Typedefs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

29

The NET Framework String c ass. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

29

Operators and express ons. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

30

Ass gnment operators. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

30

Ar thmet c operators. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

30

Re at ona and og ca operators. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

31

B tw se operators. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

32

The ternary operator. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

33

Type cast ng . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

33

Operator precedence and assoc at v ty. . . . . . . . . . . . . . . . . . . . . . . .

34

Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Chapter 4 Using functions


Dec ar ng funct on prototypes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

viii Contents

35

37
38

Dec ar ng a s mp e funct on prototype . . . . . . . . . . . . . . . . . . . . . . . .

38

Dec ar ng parameters n a funct on prototype. . . . . . . . . . . . . . . . . .

39

Dec ar ng the return type n a funct on prototype . . . . . . . . . . . . . .

39

Dec ar ng defau t va ues for funct on parameters. . . . . . . . . . . . . . .

40

Defin ng funct on bod es . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

41

Ca ng funct ons. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

45

Stepp ng through the app cat on by us ng debugger. . . . . . . . . . .

47

Understand ng oca and g oba scope . . . . . . . . . . . . . . . . . . . . . . . .

51

Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Chapter 5 Decision and loop statements


Mak ng dec s ons by us ng the if statement. . . . . . . . . . . . . . . . . . . . . . . . . .
Perform ng one-way tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

55

57
57
57

Perform ng two-way tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

61

Perform ng mu t way tests. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

62

Perform ng nested tests. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

64

Mak ng dec s ons by us ng the switch Statement. . . . . . . . . . . . . . . . . . . . .

65

Defin ng s mp e switch statements. . . . . . . . . . . . . . . . . . . . . . . . . . . .

65

Us ng fa -through n a switch statement. . . . . . . . . . . . . . . . . . . . . . .

67

Perform ng oops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

68

Us ng while oops. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

68

Us ng for oops. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

70

Us ng do-while oops. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

71

Perform ng uncond t ona jumps . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

73

Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Chapter 6 More about classes and objects


Organ z ng c asses nto header fi es and source fi es. . . . . . . . . . . . . . . . . .

75

77
78

Dec ar ng a c ass n a header fi e. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

79

Imp ement ng a c ass n a source fi e. . . . . . . . . . . . . . . . . . . . . . . . . .

81

Creat ng objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

83

In t a z ng objects by us ng constructors. . . . . . . . . . . . . . . . . . . . . . . . . . . .

84

Defin ng constructors. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

84

Member n t a zat on sts. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

86

Defin ng c ass-w de members. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

87

Defin ng c ass-w de data members. . . . . . . . . . . . . . . . . . . . . . . . . . . .

88

Defin ng c ass-w de member funct ons. . . . . . . . . . . . . . . . . . . . . . . .

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

Defin ng object re at onsh ps. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

95

Defin ng the LoyaltyScheme C ass. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

95

Imp ement ng the LoyaltyScheme c ass. . . . . . . . . . . . . . . . . . . . . . . .

96

Creat ng and us ng LoyaltyScheme objects. . . . . . . . . . . . . . . . . . . . .

97

Test ng the app cat on. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .


Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Chapter 7 Controlling object lifetimes

100
101

103

The NET approach to object fet mes. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

103

Destruct on and fina zat on. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

105

Destructors. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

105

F na zers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

106

Imp ement ng the destructor and fina zer for a c ass. . . . . . . . . . .

107

Objects and stack semant cs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

110

Copy constructors. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

113

Re at ng objects w th stack semant cs . . . . . . . . . . . . . . . . . . . . . . . .

116

Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

119

Chapter 8 Inheritance 121


What s nher tance?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Inher tance term no ogy. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

122

Inher tance and code reuse. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

122

Des gn ng an nher tance h erarchy. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .


A word on subst tutab ty . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

x Contents

121

123
123

Defin ng a base c ass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

124

Defin ng a der ved c ass. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

126

Creat ng der ved c ass objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

129

Concrete and abstract c asses. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

130

Overr d ng member funct ons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

131

Protected access. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

136

Defin ng sea ed c asses. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

137

Abstract and sea ed. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Part II

137

Defin ng and us ng nterfaces. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

138

Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

139

MICROSOFT .NET PROGRAMMING BASICS

Chapter 9 Value types


Reference types and va ue types. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

143
143

The need for va ue types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

144

Propert es of va ue types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

145

Structures. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Creat ng and us ng a s mp e struct. . . . . . . . . . . . . . . . . . . . . . . . . . .

146
146

Invest gat ng the structure. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

147

The d fferences between structures and c asses . . . . . . . . . . . . . . .

149

Imp ement ng constructors for a structure. . . . . . . . . . . . . . . . . . . .

149

Us ng one structure w th n another . . . . . . . . . . . . . . . . . . . . . . . . . .

150

Copy ng structures. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

152

Enumerat ons. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Creat ng and us ng an enumerat on. . . . . . . . . . . . . . . . . . . . . . . . . .

153
153

Us ng enumerat ons n app cat ons. . . . . . . . . . . . . . . . . . . . . . . . . .

155

Us ng memory effic ent y. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

156

Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Chapter 10 Operator overloading


What s operator over oad ng?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

156

159
159

What types need over oaded operators? . . . . . . . . . . . . . . . . . . . . .

160

What can you over oad?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

160

Ru es of over oad ng. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

161

Over oad ng operators n managed types. . . . . . . . . . . . . . . . . . . . . . . . . .

161

Over oad ng ar thmet c operators. . . . . . . . . . . . . . . . . . . . . . . . . . . .

161

Us ng stat c operator over oads. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

163

Contents
xi

What funct ons can you over oad?. . . . . . . . . . . . . . . . . . . . . . . . . . .

166

Imp ement ng og ca operators. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

167

Imp ement ng ncrement and decrement. . . . . . . . . . . . . . . . . . . . .

171

Operators and reference types. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

172

Gu de nes for prov d ng over oaded operators. . . . . . . . . . . . . . . .

173

Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Chapter 11 Exception handling


What are except ons?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

175
175

How do except ons work?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

177

Except on types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

178

Throw ng except ons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

178

Hand ng except ons. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

180

Us ng the try and catch construct. . . . . . . . . . . . . . . . . . . . . . . . . . . .

180

Custom z ng except on hand ng. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

182

Us ng the except on h erarchy. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

183

Us ng except ons w th constructors . . . . . . . . . . . . . . . . . . . . . . . . . .

184

Nest ng and rethrow ng except ons. . . . . . . . . . . . . . . . . . . . . . . . . .

185

The finally b ock. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

188

The catch() b ock. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

189

Creat ng your own except on types. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

189

Us ng safe cast for dynam c cast ng. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

191

Us ng except ons across anguages. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

192

Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

195

Chapter 12 Arrays and collections


Nat ve C++ arrays. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

xii Contents

174

197
197

Pass ng arrays to funct ons. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

200

In t a z ng arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

202

Mu t d mens ona arrays. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

202

Dynam c a ocat on and arrays. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

203

Gener c types. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

205

Managed arrays. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

207

The NET array c ass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

212

Bas c operat ons on arrays. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

213

More advanced array operat ons . . . . . . . . . . . . . . . . . . . . . . . . . . . .

215

Us ng enumerators. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

218

Other NET co ect on c asses. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

219

The List<T> c ass. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

219

The SortedList<K,V> c ass. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

222

Gener cs and temp ates. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .


The STL/CLR brary. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

224
224
227

Chapter 13 Properties 229


What are propert es?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
The two k nds of propert es. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

229
230

Imp ement ng sca ar propert es. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

231

Errors n propert es . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

232

Auto- mp emented propert es. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

233

Read-on y and wr te-on y propert es. . . . . . . . . . . . . . . . . . . . . . . . .

233

Propert es, nher tance, and nterfaces. . . . . . . . . . . . . . . . . . . . . . . .

235

Imp ement ng ndexed propert es. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

236

The Bank examp e. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

236

Creat ng Account c ass propert es. . . . . . . . . . . . . . . . . . . . . . . . . . . .

239

Add ng accounts to the Bank c ass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

240

Imp ement ng the Add and Remove methods . . . . . . . . . . . . . . . . .

240

Imp ement ng an ndexed property to retr eve accounts. . . . . . . .

241

Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Chapter 14 Delegates and events

244

245

What are de egates?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

245

What s the purpose of de egates?

246

Defin ng de egates. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

247

Imp ement ng de egates. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

247

Contents
xiii

What are events?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

254

Imp ement ng an event rece ver. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

256

Hook ng t a together. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

258

Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Chapter 15 The .NET Framework class library


What s the NET Framework?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

262

263
263

The Common Language Runt me. . . . . . . . . . . . . . . . . . . . . . . . . . . .

264

The M crosoft Intermed ate Language. . . . . . . . . . . . . . . . . . . . . . . .

264

The Common Type System. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

264

The Common Language Spec ficat on. . . . . . . . . . . . . . . . . . . . . . . .

265

The NET Framework c ass brary. . . . . . . . . . . . . . . . . . . . . . . . . . . .

265

Assemb es. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

266

Metadata. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

266

The NET Framework namespaces. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

268

Us ng namespaces n C++ app cat ons. . . . . . . . . . . . . . . . . . . . . . .

270

The System namespace. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

270

The Collections namespaces. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

272

The Collections nterfaces. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

273

The Diagnostics namespace. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

274

The IO namespace. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

274

The Windows namespaces. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

275

The Net namespaces. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

275

The ServiceModel namespaces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

275

The Xml namespaces. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

276

The Data namespaces. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

276

The Web namespaces. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

277

Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

xiv Contents

253

Imp ement ng an event source c ass. . . . . . . . . . . . . . . . . . . . . . . . . .

278

Part III

USING THE .NET FRAMEWORK

Chapter 16 Working with files

281

The System::IO namespace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

282

Imp ement ng text I/O by us ng readers and wr ters. . . . . . . . . . . . . . . . .

283

Us ng TextWriter. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

283

The FileStream c ass. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

286

Us ng TextReader. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

287

Work ng w th fi es and d rector es. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .


Gett ng nformat on about fi es and d rector es. . . . . . . . . . . . . . . .
B nary I/O. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

290
290
298

The BinaryWriter c ass. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

298

The BinaryReader c ass. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

299

Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Chapter 17 Reading and writing XML


XML and NET . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

303

305
305

The NET XML namespaces. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

306

The XML process ng c asses. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

306

Pars ng XML by us ng XmlReader. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

307

Pars ng XML w th va dat on. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

315

Wr t ng XML by us ng XmlTextWriter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

318

Us ng XmlDocument. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

322

What s the W3C DOM? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

323

The XmlDocument c ass . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

323

The XmlNode c ass. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

325

Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Chapter 18 Using ADO.NET


What s ADO NET? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

332

333
334

ADO NET data prov ders. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

334

ADO NET namespaces. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

335

ADO NET assemb es. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

336

Contents
xv

Creat ng a connected app cat on. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

336

Connect ng to a database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

337

Creat ng and execut ng a command

340

Execut ng a command that mod fies data. . . . . . . . . . . . . . . . . . . . .

341

Execut ng quer es and process ng the resu ts. . . . . . . . . . . . . . . . . .

342

Creat ng a d sconnected app cat on. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

344

D sconnected operat on us ng a DataSet. . . . . . . . . . . . . . . . . . . . . . . . . . .

345

Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

350

Chapter 19 Writing a service by using Windows Communication


Foundation 351
What s W ndows Commun cat on Foundat on?. . . . . . . . . . . . . . . . . . . . .
D str buted systems. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

352

Serv ces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

352

Connect v ty. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

353

The ABCs of WCF. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

353

Endpo nts. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

353

Address . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

354

B nd ng. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

355

Contract. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

356

Message exchange patterns. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

357

Behav ors. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

358

Creat ng a serv ce. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

359

Wr t ng a serv ce c ent. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

361

Add ng metadata to the serv ce. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

363

Access ng a serv ce by us ng a proxy. . . . . . . . . . . . . . . . . . . . . . . . .

365

Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Chapter 20 Introducing Windows Store apps


A (br ef) h story of wr t ng W ndows user nterface app cat ons. . . . . . .

xvi Contents

351

368

369
369

The W n32 API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

369

M crosoft Foundat on C asses. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

370

W ndows Forms. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

370

W ndows Presentat on Foundat on. . . . . . . . . . . . . . . . . . . . . . . . . . .

371

W ndows 8 and W ndows Store. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

371

Wh ch UI brary to choose?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

372

Introduc ng W ndows Store apps. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .


Ma n features of W ndows Store apps. . . . . . . . . . . . . . . . . . . . . . . .
Wr t ng a W ndows Store app. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

372
373
374

Creat ng your first W ndows Store app . . . . . . . . . . . . . . . . . . . . . . .

375

Exam n ng the project. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

379

Introduc ng XAML. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

380

What s XAML?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

380

XAML syntax. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

381

XAML contro s . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

382

Layout contro s. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

384

Event hand ng. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

389

C++/CX and W ndows RT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

389

W ndows RT

390

Metadata. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

390

C++/CX syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

391

Common namespaces. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

393

Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

395

Chapter 21 More about Windows Store apps

397

Bu d ng the bas c ca cu ator. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

397

Lay ng out the number buttons . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

398

Hand ng number nput . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

401

Add ng ar thmet c operat ons. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

403

Perform ng ca cu at ons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

407

Test ng the ca cu ator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

410

Improv ng the graph cs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

412

Hand ng d fferent number bases. . . . . . . . . . . . . . . . . . . . . . . . . . . .

416

Us ng app bars. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

425

Add ng shar ng. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

428

Where next?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

433

Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

433

Contents
xvii

Part IV

ADVANCED TOPICS

Chapter 22 Working with unmanaged code


Managed vs unmanaged code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

437

M xed c asses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

437

The GCHandle type. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

438

P nn ng and box ng
Inter or po nters. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

440
441

P nn ng po nters. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

441

Box ng and unbox ng . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

442

Box ng . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

443

Unbox ng. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

443

Us ng P/Invoke to ca funct ons n the W n32 API. . . . . . . . . . . . . . . . . . .

444

The DllImportAttribute c ass. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

447

Pass ng structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

449

Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

452

Chapter 23 Attributes and reflection

453

Metadata and attr butes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .


Us ng ILDASM. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Us ng predefined attr butes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

453
454
457

The Assemb yInfo cpp fi e. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

457

Us ng the predefined attr bute c asses. . . . . . . . . . . . . . . . . . . . . . . .

458

Defin ng your own attr butes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

461

Attr bute c ass propert es. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

463

Des gn cr ter a for attr bute c asses. . . . . . . . . . . . . . . . . . . . . . . . . . .

463

Wr t ng a custom attr bute. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

463

Us ng reflect on to obta n attr bute data. . . . . . . . . . . . . . . . . . . . . . . . . . .

467

The Type c ass. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

467

Access ng standard attr butes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

469

Access ng custom attr bute data. . . . . . . . . . . . . . . . . . . . . . . . . . . . .

470

Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

xviii Contents

437

472

Chapter 24 Living with COM

475

COM components and the COM Interop. . . . . . . . . . . . . . . . . . . . . . . . . . .

476

Us ng COM components from NET code . . . . . . . . . . . . . . . . . . . . . . . . . .

476

How do RCWs work?. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

476

Creat ng and us ng RCWs. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

477

Hand ng COM errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

480

Late b nd ng to COM objects. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

481

Us ng NET components as COM components. . . . . . . . . . . . . . . . . . . . . .

483

What must NET types mp ement to be used as COM objects?. . 483


Qu ck reference. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

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

Who should read this book


Th s book ex sts to he p programmers earn how to wr te app cat ons us ng C++ on the
W ndows p atform It w be usefu to those who want an ntroduct on to wr t ng NET
app cat ons us ng C++, as we as to those who want to see how to wr te W ndows Store
app cat ons
If you are spec fica y nterested n W ndows Store app cat ons, you may w sh to ook
at Build Windows 8 Apps with Microsoft Visual C++ Step by Step by Luca Regn co , Pao o
P a ors , and Roberto Brunett , pub shed by M crosoft Press


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 )

Who should not read this book


Th s book s not su tab e for comp ete beg nners to programm ng For readers who are
comp ete y new to programm ng and want to earn C++, I recommend start ng w th
a book such as Programming: Principles and Practice Using C++ by Bjarne Stroustrup,
pub shed by Add son-Wes ey
Th s book s a so not su tab e for those who want to earn standard C++ or o dersty e W n32 deve opment, because t concentrates on two M crosoft var ants (C++/CLI
and C++/CX) and does not cover top cs such as the CLR or MFC n any deta

Organization of this book


Th s book s d v ded nto four sect ons

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

Finding your best starting point in this book


The var ous sect ons of th s book cover a w de range of techno og es assoc ated w th
C++ on the W ndows p atform Depend ng on your needs and your ex st ng understand ng of C++, you may w sh to focus on spec fic areas of the book Use the fo ow ng
tab e to determ ne how best to proceed through the book
If you are

Follow these steps

New to C++

Read Part carefu y before cont nu ng to the rest


of the book.

Fam ar w th OO programm ng but not w th C++

Read Part carefu y, but you can om t Chapter 2.

Fam ar w th C++

Rev ew Part , ook ng for the d fferences be


tween standard C++ and C++/CL .

Fam ar w th .NET, but not W ndows Store


app cat ons.

Read Chapters 20 and 21.

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

Conventions and features in this book


Th s book presents nformat on us ng convent ons des gned to make the nformat on
readab e and easy to fo ow

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

One of W ndows 7, W ndows 8, W ndows Server 2008 w th Serv ce Pack 2, or


W ndows Server 2008 R2 Note that f you want to bu d and run the W ndows
Store app cat ons featured n Chapters 20 and 21, you w need W ndows 8

V sua Stud o 2012, any ed t on

A computer that has a 1 6 GHz or faster processor (2 GHz s recommended)

1 GB (32 B t) or 2 GB (64 B t) RAM

3 5 GB of ava ab e hard d sk space

5400 RPM hard d sk dr ve

D rectX 9 capab e v deo card runn ng at 1024 x 768 or h gher-reso ut on d sp ay

DVD-ROM dr ve ( f nsta ng V sua Stud o from DVD)

Internet connect on to down oad software or chapter examp es

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!

Errata and book support


Weve made every effort to ensure the accuracy of th s book and ts compan on content Any errors that have been reported s nce th s book was pub shed are sted on our
M crosoft Press s te at ore y com
http://aka.ms/VCCLISbS/errata
If you find an error that s not a ready sted, you can report t to us through the
same page
If you need add t ona support, ema M crosoft Press Book Support at mspinput@
microsoft.com
P ease note that product support for M crosoft software s not offered through the
addresses above

Introductionxxv

We want to hear from you


At M crosoft Press, your sat sfact on s our top pr or ty, and your feedback our most
va uab e asset P ease te us what you th nk of th s book at
http://www.microsoft.com/learning/booksurvey
The survey s short, and we read every one of your comments and deas Thanks n
advance for your nput!

Stay in touch
Lets keep the conversat on go ng! Were on Tw tter http://twitter.com/MicrosoftPress

xxviIntroduction

PAR T I

Getting started with


C++ .NET
CHAPTER 1

He o C++!

CHAPTER 2

Introduc ng object-or ented programm ng . . . . . .

13

CHAPTER 3

Var ab es and operators . . . . . . . . . . . . . . . . . . . . . . .

23

CHAPTER 4

Us ng funct ons

37

CHAPTER 5

Dec s on and oop statements

57

CHAPTER 6

More about c asses and objects . . . . . . . . . . . . . . . .

77

CHAPTER 7

Contro ng object fet mes . . . . . . . . . . . . . . . . . . .

103

CHAPTER 8

Inher tance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

121

CHAPTER 1

Hello C++!
After completing this chapter, you will be able to

Recogn ze C++ funct ons

Recogn ze C++ keywords and dent fiers

Create a C++ app cat on

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

Your first C++/CLI application


Its t me to get our hands d rty w th a s mp e C++/CLI app cat on Of course, no programm ng book
wou d be comp ete w thout nc ud ng the customary He o Wor d app cat on, so ets start w th that
using namespace System;
int main()
{
Console::WriteLine("Hello, World!");
return 0;
}

Th s short app cat on

ustrates some fundamenta C++/CLI concepts

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

The main function


Why s the on y funct on n the prev ous examp e ca ed main? The s mp e answer s that the code
wont comp e f t snt! However, t m ght be more usefu to exp a n how the anguage works
A norma C++ app cat on conta ns many funct ons (and a so many c asses, as s d scussed n
Chapter 2, Introduc ng object-or ented programm ng) How does the comp er know wh ch funct on
shou d be ca ed first? Obv ous y, you cant a ow the comp er to just random y choose a funct on The
ru e s that the comp er a ways generates code that ooks for a funct on named main If you om t the
main funct on, the comp er reports an error and doesnt create a fin shed executab e app cat on

4Microsoft Visual C++/CLI Step by Step

Outs de of these restr ct ons, any dent fier w


ed, such as the fo ow ng

work However, some cho ces are not recommend-

Identifier

Reason its not recommended

ma n

Cou d be confused w th the funct on ma n.

NT

Too c ose to the reserved word nt.

B4ugotxtme

Just too crypt c!

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.

Creating an executable applicationtheory


Severa stages are requ red to bu d an executab e app cat on; M crosoft V sua Stud o 2012 he ps you
accomp sh th s by automat ng them To exam ne and understand these stages, however, ets ook at
them br efly You see these stages aga n ater n the chapter when we bu d our first app cat on

Editing the application source files


Before you can create an app cat on, you must wr te someth ng V sua Stud o 2012 prov des an
ntegrated C++ ed tor, comp ete w th co or syntax h gh ght ng and M crosoft Inte Sense to show
funct on parameter nformat on and prov de word comp et on

Compiling the source files


The C++/CLI comp er s the too for convert ng text source fi es nto someth ng that can be executed
by a computer processor The comp er takes your source fi es (wh ch usua y have a .cpp extens on)
and bu ds them nto e ther a stand-a one executab e fi e (w th a .exe extens on) or a brary fi e to be
used n other projects (w th a .dll extens on)

Standard C++ and C


If you have ever worked w th standard C++ or C, you m ght be fam ar w th the dea of comp ng to object fi es and then nk ng w th brar es to bu d the fina executab e fi ewh ch s
common y referred to s mp y as an executab e A though you can comp e to the equ va ent of
an object fi e (ca ed a module n the NET wor d) and then nk those together by us ng a too
ca ed the assembly linker, V sua Stud o takes you stra ght from source to executab e w thout
you see ng the ntermed ate step

6Microsoft Visual C++/CLI Step by Step

Running and testing the application


After you have successfu y bu t the app cat on, you need to run t and test t
For many deve opment env ronments, runn ng and test ng s often the most d fficu t part of the
app cat on deve opment cyc e However, V sua Stud o 2012 has yet another ace up ts s eeve the
ntegrated debugger The debugger has a r ch set of features w th wh ch you can eas y perform runt me debugg ng, such as sett ng breakpoints and variable watches

Creating an executable applicationpractice


Go ahead and start V sua Stud o 2012 An nv t ng y b ank w ndow appears on your screen

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

press Ctr +Sh ft+N )

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

to an appropr ate d rectory


8Microsoft Visual C++/CLI Step by Step

4. C ck OK to create the project

The w zard correct y n t a zes a the comp er sett ngs for a conso e project

Editing the C++ source code


The w zard creates a project for you w th a the fi es needed for a s mp e conso e app cat on It a so
opens the ma n source fi e n the ed tor that conta ns just the code we want

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

Building the executable


The next step s to bu d the executab e The term build n V sua Stud o 2012 refers to comp ng and
nk ng the app cat on V sua Stud o comp es any source fi es that have changed s nce the ast bu d
and f no comp e errors were generatedperforms a nk
To bu d the executab e, on the Bu d menu, c ck Bu d So ut on or press F7

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

conta n a st of errors and warn ngs

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

How should you treat warnings?


A ways treat warn ngs as errors n other words, get r d of them Warn ngs are there for a
reason; theyre te ng you that your code s not correct

10Microsoft Visual C++/CLI Step by Step

Executing the application


After youve e m nated a errors and youve successfu y bu t the project, you can fina y execute the
app cat on On the Debug menu, c ck Start W thout Debugg ng to run the app cat on You can a so
press Ctr +F5 to execute the app cat on
You see the output of your app cat on, w th the message Press any key to cont nue at the bottom of the output Th s ne s added by the IDE so that the conso e w ndow doesnt s mp y d sappear
when the app cat on has fin shed runn ng

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

Create a new project n V sua Stud o 2012.

C ck F e New Project, or press Ctr +Sh ft+N. n the Express


vers on, on the F e menu, c ck New Project.

Add a fi e to a project.

C ck F e New F e, or press Ctr +N.

Bu d a V sua Stud o 2012 project.

C ck Bu d Bu d So ut on, or press Ctr +Sh ft+B.

Execute a program from w th n V sua Stud o 2012.

C ck Debug Start W thout Debugg ng, or press Ctr +F5.

Chapter 1 He o C++! 11

CHAPTER 2

Introducing object-oriented
programming
After completing this chapter, you will be able to

Descr be the key concepts of object-or ented programm ng

Understand how these concepts are supported by C++ anguage constructs

Understand the major deve opment benefits of object-or ented programm ng

Create and use s mp e c asses

What is object-oriented programming?


Object-or ented programm ng s a parad gm that prov des a natura way to deve op many k nds of
systems We perce ve the wor d as cons st ng of objects tab es, cha rs, computers, cars, bank accounts, footba games, and so on It s a natura human tra t to try to organ ze these objects, arrangng them nto some form of c ass ficat on and choos ng to h gh ght certa n features of objects n preference to others So, dogs and cats are mamma s, toasters and refr gerators are app ances, sw mm ng
and tenn s are sports, Toyotas and Fords are cars, trucks and cars are veh c es, and so on
There can be many eve s to these categor es and many ways to c ass fy the objects n the wor d
How peop e c ass fy th ngs depends to a arge extent on what they want to do w th them as we as
the re evant features of the objects themse ves For examp e, a reta er of househo d app ances s
ke y to use d fferent categor esposs b y deeper and r cherfor ts products than a typ ca homeowner When group ng objects nto c ass ficat on schemes, we a so tend to h gh ght certa n attr butes
of objects n preference to others For nstance, to an eng neer, a cars co or m ght not matter, but t
m ght figure heav y n the menta mode of car c ass ficat ons used by a Ferrar sa esperson
Object-or ented programm ng ets us bu d h erarch es of objects, creat ng them and defin ng how
they are re ated As ong ago as the 1960s, researchers rea zed that many computer programs mode ed ent t es that can be named, and that the r propert es and behav or can be descr bed Examp es of
such objects m ght be bank accounts, arrays, fi es, and users, a of wh ch are ana ogous to objects n
the rea wor d


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

Features of object-oriented programming languages


Ive a ready po nted out that object-or ented programm ng means defin ng and bu d ng h erarch es
of objects and defin ng the r propert es and behav or You can do th s to a certa n extent n any
programm ng anguage, just the same as you cou d, theoret ca y, take a tr p over the Rock es n a go f
cart, but t s much eas er to do object-or ented programm ng f you use a anguage that s des gned
to support object-or ented programm ng methods
Object-or ented programm ng anguages such as C++ and C# are character zed by three key
features encapsulation, inheritance, and polymorphism These features support th s natura process of
dent fy ng and c ass fy ng objects Lets take a c oser ook at each one

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

Chapter 2 ntroduc ng object or ented programm ng 15

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

Classes and objects


Up to th s po nt n the chapter, the terms c ass and object have been used fa r y nterchangeab y
However, c asses and objects arent the same th ng, and we need to c ar fy the d fferences between
these terms As the name mp es, object-or ented programm ng s about objects An object s composed of data that descr bes the object and the operat ons that can be performed on the object
However, when you create an app cat on n C++, you define c asses, not objects
A class s a user-defined type; t encapsu ates both the data and the methods that work on that
data W th the except on of stat c funct ons, you cannot use c asses d rect y A c ass s ke a temp ate,
wh ch s used to create ( nstant ate) objects Just as you have to dec are an int var ab e before you can
use t, you a so have to nstant ate an object of the c ass before you can use t
For examp e, you wou d not define an Animal object Instead, you wou d define an Animal
c assa ong w th ts attr butes and methods The c ass represents the concept, so the Animal c ass
does not represent a spec fic an ma but the c ass of a an ma s When you want to use an Animal
object, you have to nstant ate an Animal object from the c ass The c ass can be cons dered as the abstract representat on of an ent ty, whereas the nstant at on of the c assthe object s the concrete
representat on

Benefits to the development life cycle


There are three key benefits to object-or ented programm ng comprehensibility, reusability, and
extensibility Break ng code down nto c asses makes t more comprehens b e by mpos ng a structure
as programs grow arger and arger The dea s to assemb e object-or ented systems from prewr tten
c asses and to make the requ red mod ficat ons to support the new requ rements by us ng nher tance

16Microsoft Visual C++/CLI Step by Step

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

The New Project d a og box opens


3. In the nav gat on pane on the eft, under Temp ates, c ck V sua C++, and then c ck CLR
4. In the center pane choose CLR Conso e App cat on
5. Toward the bottom of the d a og box, n the Name box, type Animals
6. C ck the Locat on box and se ect a ocat on for the new project (or c ck Browse to find t), and

then c ck OK

Chapter 2 ntroduc ng object or ented programm ng 17

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

the Source F es fo der, doub e-c ck the An ma s cpp fi e


8. Immed ate y under the using namespace System; ne, add the fo ow ng c ass defin t on
ref class Animal
{
int legs;
String ^name;
};

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

the first var ab e dec arat on

18Microsoft Visual C++/CLI Step by Step

ref class Animal


{
public:
int legs:
String ^name;
};

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-

ng method dec arat ons or mp ementat on nes


void SetName(String ^nm)
{
name = nm;
}
String^ GetName()
{
return name;
}

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

Chapter 2 ntroduc ng object or ented programm ng 19

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

20Microsoft Visual C++/CLI Step by Step

4. Add the fo ow ng nes


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

Now, ts t me to bu d the app cat on


5. On the Bu d menu, c ck Bu d So ut on or use the keyboard shortcut F6

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

Chapter 2 ntroduc ng object or ented programm ng 21

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

Debug menu, or use the keyboard shortcut Ctr +F5

Quick reference
To

Do this

Create a c ass.

Use the keyword class.

Contro the v s b ty of var ab es and methods.

Use the access contro keywords public, private, or


protected, fo owed by a co on (:).

Dec are a reference type c ass.

P ace the ref keyword before the class spec fier.

Dec are a va ue type c ass.

P ace the value keyword before the class spec fier.

nstant ate a reference type c ass object.

Use the name of the c ass when dec ar ng an object; for


examp e:
Animal cat;

22Microsoft Visual C++/CLI Step by Step

CHAPTER 3

Variables and operators


After completing this chapter, you will be able to:

Dec are (create) var ab es

Use the bu t- n C++ data types

Use the M crosoft NET Framework Str ng c ass

Ass gn va ues to a var ab e

Create express ons by us ng the C++ operators

Cast (change) the type of a var ab e

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

The fundamental data types


C++ has a bu t- n set of data types, as out ned n the fo ow ng tab e


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.

When you dec are a var ab e, the comp er does the fo ow ng

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!

Chapter 3 Var ab es and operators 25

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.

Declaring multiple variables


You can dec are severa var ab es of the same type n the same statement s mp y by separat ng them
w th commas, as demonstrated n the fo ow ng
int x = 10, y, z = 11;

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

Assigning values to variables


You ass gn a va ue to a var ab e by us ng the ass gnment operator = (the equa s gn) The va ue on the
r ght s de of the operator s stored n the var ab e, wh ch s on the eft s de When ass gn ng a va ue to
a var ab e, the va ue must be ong to the same type as the var ab e, t must be a type for wh ch C++
w perform an ass gnment convers on (such as between float and ntegra types), or t must be exp ct y converted (cast) to the correct type

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;

You g ve the name of the type to wh ch to convert, fo owed by the va ue n parentheses


Th s process s ca ed casting, and t can be rather dangerous because youre d rect ng the
comp er to app y a convers on that t otherw se wou d not do, and youd better be sure youre
correct

26Microsoft Visual C++/CLI Step by Step

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

Handles and pointers


In standard C++, a po nter s a var ab e that ho ds the memory address of another var ab e or funct on, wh ch means that you can use a po nter to refer nd rect y to a var ab e
In C++/CLI, however, the runt me s manag ng memory on your beha f, and t reserves the r ght to
move th ngs around to max m ze the ava ab e free memory Th s means that an object m ght not stay
at the same address throughout ts fet me; thus, the address stored n your po nter m ght become
out of date, ead ng to prob ems f you try to use t
For th s reason po nters, n the trad t ona C++ sense, are not used n C++/CLI Instead, you use
handles (a so known as tracking handles), wh ch a so conta n the address of a var ab e but wh ch w
be updated by the runt me f t has to move the var ab e around
A though a hand e conta ns an address and therefore can store a memory address of any data
type, hand e var ab es are dec ared to be data-type spec fic A hand e to a Person object cant store
the address of an Account A hand e var ab e s dec ared n the same way as the data-type var ab e,
but the hand e operator ^ (caret character) s prepended to the var ab e name
Person ^pp;
Account ^ac;

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

Person ^pp = gcnew Person("Fred");

Chapter 3 Var ab es and operators 27

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

28Microsoft Visual C++/CLI Step by Step

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;

The .NET Framework String class


The String c ass s not a bu t- n data type ke int or long; t s a part of the NET Framework Because
String snt a bu t- n type, you must nc ude some fi es n your project before the comp er w et
you use t Code that wants to use the String c ass needs to nc ude the fo ow ng ne at the top of ts
source code fi e
using namespace System;

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

Chapter 3 Var ab es and operators 29

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.

Operators and expressions


Express ons are bu t by us ng operators that work w th datathe operandsto g ve a resu t Look at
th s examp e
remuneration = salary + bonus;

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;

In th s examp e, a three var ab esnoOfMammals, noOfDogs, and noOfCatsare set to 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

30Microsoft Visual C++/CLI Step by Step

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

Relational and logical operators


Re at ona operators are used to compare two va ues or express ons, return ng a va ue of true or fa se
C++ has s x re at ona operators, as shown n the fo ow ng code
a
a
a
a
a
a

> 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

Chapter 3 Var ab es and operators 31

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

if both a and b are true


if a is greater than b and a
c
if either a or b are true
if either a is greater than b
than c

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

// returns false if a is true


// returns true if a is false

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;

// The bits of a will be shifted two bits to the left


// and the value of 20 assigned to a.

32Microsoft Visual C++/CLI Step by Step

a = 5;
a = a >> 2;

// The bits of a will be shifted two bits to the


// right and the value of 1 assigned to a.

The ternary operator


The ternary operator ?: (a quest on mark and a co on) acts ke an n ne if statement (See Chapter 5
for more nformat on on if statements ) The express on to the eft of the quest on mark s eva uated;
f t s true, the va ue or express on between the quest on mark and the co on w be returned If t s
fa se, the va ue or express on after the co on w be returned
int a;
bool b;
b = true;
a = b ? 1 : 2;
b = false;
a = b ? 1 : 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;

// old C-style cast

b = static_cast<double>(a);

// C++ static cast

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

Chapter 3 Var ab es and operators 33

Quick reference
To

Do this

Dec are a var ab e.

Spec fy the type, fo owed by spaces and then the var ab e


name, fo owed by a sem co on. For examp e:
int number1;
long longNumber1;

Ass gn va ues to a var ab e.

Use the ass gnment operator =.

Group homogenous data together.

Use an array.

Prevent data from be ng changed.

Make the var ab e a constant. For examp e:


const int x = 10;

Restr ct the va ues a var ab e can accept to a sma set.

Dec are an enumerated constant, and dec are the var ab e


to be of that type.

Access a String c ass.

Use the .NET String c ass.

Convert one data type to another.

Use the static cast<> operator.

Overr de defau t operator precedence, or make the code


more readab e.

Use parentheses to group operators.

Chapter 3 Var ab es and operators 35

CHAPTER 4

Using functions
After completing this chapter, you will be able to:

Dec are funct on prototypes

Define funct on bod es

Ca funct ons

Dea w th oca and g oba var ab e scope

Define and use over oaded 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

Why use functions?


There are many good reasons for d v d ng an app cat on nto funct ons Here are three of them

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

Declaring function prototypes


A funct on prototype s a s ng e- ne statement that ntroduces the name of a funct on to the comp er The prototype a so nd cates what types of parameters can be passed nto the funct on and
what type of va ue the funct on returns The comb nat on of nformat on about a funct ons name and
parameters s ca ed the function signature

Declaring a simple function prototype


The fo ow ng examp e shows a s mp e funct on prototype
void DisplayWelcome();

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.

A note on function naming


Some anguages have very strong nam ng convent ons that gu de how you shou d construct
funct on and var ab e names C++ has never had such a un versa convent on, but f youre
wr t ng C++/CLI code, you wou d be w se to adopt the convent on used n the M crosoft NET
brar es Funct on names shou d start w th a cap ta etter, and nd v dua words w th n the name
shou d a so be cap ta zed, as n DisplayWelcome or CreateNewCustomerOrder The except on to
th s convent on s the entry po nt main, wh ch s trad t ona y typed n owercase etters

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

Declaring parameters in a function prototype


Funct ons can take parameters to make them more gener c You must dec are the data types for these
parameters n the funct on prototype
In th s exerc se, you w

dec are a funct on prototype that uses parameters

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

Declaring the return type in a function prototype


As we as spec fy ng nput parameters for a funct on, you must a so spec fy a return type for the funct on As you saw ear er, the void return type nd cates that the funct on does not return a va ue
In th s exerc se, you w

see how to spec fy a non-void return type for a funct on

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

Chapter 4 Us ng funct ons 39

Th s funct on prototype dec ares a funct on named GetInvestmentAmount The funct on


doesnt take any parameters, but t returns a doub e
3. Add another funct on prototype as fo ows, mmed ate y be ow the double GetInvestment

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

4. Bu d your app cat on

Declaring default values for function parameters


When you dec are a funct on prototype, you can spec fy defau t va ues for some or a of ts parameters Defau t va ues are usefu for parameters that usua y have the same va ue each t me the funct on
s ca ed Spec fy ng a defau t va ue for a funct on parameter means that you can om t the parameter
va ue when you ca the funct on; the comp er w subst tute the defau t va ue on your beha f
In th s exerc se, you w
ear er

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

3. Mod fy the funct on prototype as fo ows to define defau t parameter va ues


int GetInvestmentPeriod(int min=10, int max=25);

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

40Microsoft Visual C++/CLI Step by Step

Defining function bodies


In the prev ous sect on, you earned how to dec are funct on prototypes Reca that a funct on
prototype spec fies the name of a funct on, ts parameter st, and ts return type However, funct on
prototypes do not conta n any executab e statements; they do not nform you as to what the funct on
w do when t s ca ed
To prov de the behav or for a funct on, you must define a funct on body The funct on body conta ns executab e statements to perform the des red operat ons n the funct on In th s sect on, you w
define funct on bod es for a the funct on prototypes ntroduced ear er

Defining a simple function body


The fo ow ng examp e shows a s mp e funct on body, correspond ng to the DisplayWelcome funct on
prototype from ear er n chapter
void DisplayWelcome()
{
Console::WriteLine("---------------------------------------");
Console::WriteLine(
"Welcome to your friendly Investment Planner");
Console::WriteLine("---------------------------------------");
return;
}

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

add the DisplayWelcome funct on body to your C++/CLI app cat on

1. Cont nue work ng w th the project you created ear er n th s chapter


2. Locate the end of the main funct on On the next ne, define the DisplayWelcome funct on

body as fo ows
void DisplayWelcome()
{
Console::WriteLine("--------------------------------");
Console::WriteLine(
"Welcome to your friendly Investment Planner");

Chapter 4 Us ng funct ons 41

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.

Defining a function body that uses parameters


When you define a funct on body that uses parameters, you must define exact y the same number
and types of parameters as n the funct on prototype Th s s qu te reasonab e The who e po nt of the
funct on prototype s to ntroduce the exact s gnature of the funct on

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

DisplayProjectedValue funct on body


void DisplayProjectedValue(double amount, int years, double rate)
{

3. Define some oca var ab es w th n the funct on


double rateFraction = 1 + (rate/100);
double finalAmount = amount * Math::Pow(rateFraction, years);
finalAmount = Math::Round(finalAmount, 2);

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

42Microsoft Visual C++/CLI Step by Step

The express on Math::Pow(rateFraction, years) shows how to ra se a number to a power n


C++/CLI For examp e, Math::Pow(1.06, 3) s equ va ent to 1 06 * 1 06 * 1 06
The express on Math::Round(finalAmount, 2) rounds finalAmount to two dec ma p aces For
examp e, f finalAmount s 1000 775, the rounded va ue w be 1000 78
4. Add the fo ow ng statements to the funct on to d sp ay the resu t of the ca cu at ons
Console::Write("Investment amount: ");
Console::WriteLine(amount);
Console::Write("Growth rate [%]: ");
Console::WriteLine(rate);
Console::Write("Period [years]: ");
Console::WriteLine(years);
Console::Write("Projected final value of investment: ");
Console::WriteLine(finalAmount);
return;
}

5. Bu d your app cat on

Defining a function body that returns a value


When you define a funct on w th a non-void return type, you must return an appropr ate va ue from
the funct on To return a va ue, use the return keyword fo owed by the va ue that you want to return

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

Chapter 4 Us ng funct ons 43

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

44Microsoft Visual C++/CLI Step by Step

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

Th s s a s mp e examp e because the funct on doesnt take any parameters or return a va ue


If you want to ca a funct on that returns a va ue, you can ass gn the return va ue to a var ab e The
fo ow ng examp e ca s the GetInvestmentAmount funct on and ass gns the return va ue (a double) to
a oca var ab e named sum
double sum = GetInvestmentAmount();

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.

Chapter 4 Us ng funct ons 45

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

Calling functions in the sample application


In th s exerc se, you w

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-

ng statement, wh ch ca s the DisplayWelcome funct on


DisplayWelcome();

3. Add the fo ow ng statements to d sp ay an

ustrat on of nvestment growth

Console::WriteLine("\nIllustration...");
DisplayProjectedValue(10000, 25, 6.0);

The DisplayProjectedValue funct on ca d sp ays the va ue of 10,000 after 25 years at a growth


rate of 6 percent
4. Next add the fo ow ng statements to ask the user how much he wants to nvest and for how

ong
Console::WriteLine("\nEnter details for your investment:");
double sum = GetInvestmentAmount();
int period = GetInvestmentPeriod(5, 25);

The GetInvestmentAmount and GetInvestmentPeriod funct on ca s return these va ues

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

46Microsoft Visual C++/CLI Step by Step

// Try to use default value


// for just the first
// parameter illegal.

5. Add the fo ow ng statements to ca cu ate and d sp ay the projected fina va ue of th s nvest-

ment, assum ng a growth rate of 6 percent


Console::WriteLine("\nYour plan...");
DisplayProjectedValue(sum, period, 6.0);

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

Stepping through the application by using debugger


In th s exerc se, you w step through the app cat on by us ng the debugger Do ng so w he p you
understand how the flow of contro passes from one funct on to another n your app cat on Th s exerc se a so ustrates the concept of var ab e scope You w see how oca var ab es n a funct on come
nto scope dur ng the funct ons execut on and d sappear from scope at the end of the funct on
1. Open the project from the prev ous exerc se
2. Locate the main funct on
3. In the gray border to the eft of the code, c ck next to the DisplayWelcome funct on ca to n-

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.

Chapter 4 Us ng funct ons 47

4. Start the debugg ng sess on by press ng F5

After the app cat on oads, t executes and stops at the breakpo nt n the main funct on

A ye ow arrow appears n the marg n next to the DisplayWelcome funct on ca The ye ow


arrow nd cates that th s s the next statement to be executed
5. Press F11 to step nto the DisplayWelcome 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

48Microsoft Visual C++/CLI Step by Step

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

Chapter 4 Us ng funct ons 49

7. Press F10 to step over the Console::WriteLine funct on

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

W ndows, and then c ck Loca s


The oca var ab es n th s funct on appear

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

50Microsoft Visual C++/CLI Step by Step

11. In main, press F10 to step over the Console::WriteLine statement


12. Press F11 to step nto the GetInvestmentAmount funct on Step through the statements n th s

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.

Understanding local and global scope


The prev ous exerc se demonstrated how each funct on defines ts own scope for oca var ab es The
oca var ab es are created dur ng funct on execut on and are automat ca y destroyed at the end of
the funct on, wh ch means you can qu te happ y have var ab es w th the same name n d fferent funct ons w thout nterference

Chapter 4 Us ng funct ons 51

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

use th s g oba var ab e

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

numberOfYourFunctionsCalled var ab e, as shown n the fo ow ng

52Microsoft Visual C++/CLI Step by Step

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

the va ue of the numberOfYourFunctionsCalled var ab e

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

Chapter 4 Us ng funct ons 53

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

funct on ca so that you pass on y two parameters nto the funct on


DisplayProjectedValue(sum, period);

4. Define the new DisplayProjectedValue funct on body as fo ows, p ac ng t after the ex st ng

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

54Microsoft Visual C++/CLI Step by Step

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

Dec are a funct on prototype.

Spec fy the return type of the funct on, fo owed by the


funct on name, fo owed by the parameter st enc osed n
parentheses. Remember to nc ude the sem co on at the
end of the funct on prototype. For examp e:
double MyFunction(int p1, short p2);

Define defau t parameters.

Define defau t parameters n the funct on prototype,


f requ red. Use an = operator, fo owed by the defau t
va ue. For examp e:
double MyFunction(int p1, short p2=100);

Define a funct on body.

Spec fy the return type of the funct on, fo owed by the


funct on name, fo owed by the parameter st enc osed
n parentheses. Do not spec fy defau t parameters here.
Define the funct on body w th n braces. For examp e:
double MyFunction(int p1, short p2)
{
int n = p1 + p2;
...
}

Return a va ue from a funct on.

Use the return keyword, fo owed by the va ue that you


want to return. For examp e:
return (p1 + p2) / 2.00;

Ca a funct on.

Spec fy the funct on name and pass parameter va ues


w th n parentheses. f the funct on returns a va ue, you
can ass gn t to a var ab e. For examp e:
double result = MyFunction(100, 175);

Define and use g oba var ab es.

Define the g oba var ab e outs de of any funct on. Use


the var ab e n any subsequent funct on n the source fi e.
For examp e:
int myGlobal = 0;
void MyFunction()
{
myGlobal++;
...
}

Chapter 4 Us ng funct ons 55

CHAPTER 5

Decision and loop statements


After comp et ng th s chapter, you w

be ab e to

Make dec s ons by us ng the if statement

Make mu t way dec s ons by us ng the switch statement

Perform oops by us ng the while, for, and do-while statements

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

Making decisions by using the if statement


The most common way to make a dec s on n C++/CLI s to use the if statement You can use the if
statement to perform a one-way test, a two-way test, a mu t way test, or a nested test Lets cons der
a s mp e one-way test first

Performing one-way tests


The fo ow ng examp e shows how to define a one-way test n C++/CLI
if (number < 0)
Console::WriteLine("The number is negative");
Console::WriteLine("The end");

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

// Note the spurious semicolon

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

the fo ow ng funct on prototypes (you w

mp ement a these funct ons dur ng th s chapter)

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;
}

58Microsoft Visual C++/CLI Step by Step

4. Imp ement the GetMonth funct on as fo ows


int GetMonth()
{
Console::Write("Month? ");
String ^input = Console::ReadLine();
int month = Convert::ToInt32(input);
return month;
}

Th s s a s mp fied mp ementat on; ater n th s chapter, you w


sure that the user enters a va d month

enhance the funct on to en-

5. Imp ement the GetDay funct on as fo ows


int GetDay(int year, int month)
{
Console::Write("Day? ");
String ^input = Console::ReadLine();
int day = Convert::ToInt32(input);
return day;
}

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

Later n th s chapter you w


format

enhance th s funct on to d sp ay the date n a more user-fr end y

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

Chapter 5 Dec s on and oop statements 59

// Simplified test for now assume there are 31 days in


// every month :-)
if (month >= 1 && month <= 12 && day >= 1 && day <= 31)
{
DisplayDate(year, month, day);
}
Console::WriteLine("\nThe end\n");

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

60Microsoft Visual C++/CLI Step by Step

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

Performing two-way tests


The fo ow ng code shows how to define a two-way test for the Ca endar Ass stant app cat on
if (month >= 1 && month <= 12 && day >= 1 && day <= 31)
{
DisplayDate(year, month, day);
}
else
{
Console::WriteLine("Invalid date");
}
Console::WriteLine("\nThe end\n");

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

Chapter 5 Dec s on and oop statements 61

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

Performing multiway tests


You can arrange if-else statements n a cascad ng fash on to perform mu t way dec s on mak ng
The fo ow ng code shows how to use a mu t way test to determ ne the max mum number of days
(maxDay) n a month
int maxDay;
if (month == 4 || month == 6 || month == 9 || month == 11)
{
maxDay = 30;
}
else if (month == 2)
{
maxDay = 28;
}
else
{
maxDay = 31;
}

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

determ ne the max mum a owab e number of days


int GetDay(int year, int month)
{
int maxDay;
if (month == 4 || month == 6 || month == 9 || month == 11)
{
maxDay = 30;
}
else if (month == 2)
{
maxDay = 28;
}
else
{
maxDay = 31;
}
Console::Write("Day [1 to ");
Console::Write(maxDay);
Console::Write("]? ");
String ^input = Console::ReadLine();
int day = Convert::ToInt32(input);
return day;
}

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

Chapter 5 Dec s on and oop statements 63

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 )

Performing nested tests


It s poss b e to nest tests w th n one another Th s makes t poss b e for you to perform more comp ex
og ca operat ons The fo ow ng code shows how to use nested tests to accommodate eap years correct y n the Ca endar Ass stant app cat on
int maxDay;
if (month == 4 || month == 6 || month == 9 || month == 11)
{
maxDay = 30;
}
else if (month == 2)
{
bool isLeapYear = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
if (isLeapYear)
{
maxDay = 29;
}
else
{
maxDay = 28;
}
}
else
{
maxDay = 31;
}

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

code just descr bed to test for eap years


3. Bu d and run the app cat on Type the year 1996 and the month 2 The app cat on prompts

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

prompts you to enter a day between 1 and 28


5. Run the app cat on severa more t mes us ng the test data from the prev ous tab e

Making decisions by using the switch Statement


Now that you have seen how the if statement works, ets take a ook at the switch statement Us ng
the switch statement, you can test a s ng e var ab e and execute one of severa branches depend ng
on the var ab es va ue

Defining simple switch statements


The examp e that fo ows shows the syntax for the switch statement The switch statement tests the
numberOfSides n a shape and d sp ays a message to descr be that shape

Chapter 5 Dec s on and oop statements 65

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

Console::Write(month) statement w th a switch statement that d sp ays the month as a str ng


switch (month)
{
case 1: Console::Write("January");
case 2: Console::Write("February");
case 3: Console::Write("March");
case 4: Console::Write("April");
case 5: Console::Write("May");
case 6: Console::Write("June");
case 7: Console::Write("July");
case 8: Console::Write("August");
case 9: Console::Write("September");
case 10: Console::Write("October");
case 11: Console::Write("November");
case 12: Console::Write("December");
default: Console::Write("Unknown");
}

break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;
break;

3. Bu d the app cat on


4. Run the app cat on severa t mes, typ ng a d fferent month each t me Ver fy that the app ca-

t on d sp ays the correct month name each t me

Using fall-through in a switch statement


If you om t the break statement at the end of a case branch, flow of contro cont nues on to the next
statement Th s process s ca ed fall-through Th s can be usefu to avo d dup cat on of code, but be
carefu not to do t acc denta y
The fo ow ng examp e ustrates why fa -through m ght be usefu Th s examp e tests a owercase
etter to see f t s a vowe or a consonant
char lowercaseLetter;
// Single lowercase letter, for example 'a'
...
switch (lowercaseLetter)
{
case 'a':
case 'e':
case 'i':
case 'o':
case 'u': Console::Write("Vowel"); break;
default:

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

Chapter 5 Dec s on and oop statements 67

In th s exerc se, you w


users date

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

code after the ne Console::Write(day) to d sp ay the season


switch (month)
{
case 12:
case 1:
case 2: Console::WriteLine(" [Winter]"); break;
case 3:
case 4:
case 5:

Console::WriteLine(" [Spring]"); break;

case 6:
case 7:
case 8:

Console::WriteLine(" [Summer]"); break;

case 9:
case 10:
case 11: Console::WriteLine(" [Fall]"); break;
}

3. Bu d the app cat on


4. Run the app cat on severa t mes, typ ng a d fferent month each t me Ver fy that the app ca-

t on d sp ays the correct season name each t me

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

Using while loops


A while oop cont nues execut ng ts body for as ong as the cond t on n parentheses eva uates to
true The fo ow ng examp e shows how to wr te a s mp e while oop n C++/CLI
68Microsoft Visual C++/CLI Step by Step

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

In th s exerc se, you w


dates

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++;

// Increment the loop counter

Chapter 5 Dec s on and oop statements 69

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

Using for loops


The for oop s an a ternat ve to the while oop It prov des more contro over the way n wh ch the
oop executes
The fo ow ng examp e shows how to wr te a s mp e for oop n C++/CLI Th s examp e has exact y
the same effect as the while oop
for (int count = 1; count <= 5; count++)
{
Console::WriteLine(count * count);
}
Console::WriteLine("The end");

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

Using do-while loops


The th rd oop construct you ook at here s the do-while oop (remember, theres st the for-each
oop, wh ch you w meet ater) The do-while oop s fundamenta y d fferent from the while and for
oops because the test comes at the end of the oop body, wh ch means that the oop body s a ways
executed at east once

Chapter 5 Dec s on and oop statements 71

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

72Microsoft Visual C++/CLI Step by Step

while (month < 1 || month > 12);


return month;
}

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;
}

4. Bu d and run the app cat on


5. Try to type an nva d month The app cat on keeps ask ng you to enter another month unt

you type a va ue between 1 and 12, nc us ve


6. Try to type an nva d day The app cat on keeps ask ng you to enter another day unt you

type a va d number (wh ch depends on your chosen year and month)

Performing unconditional jumps


C++/CLI prov des two keywordsbreak and continuew th wh ch you can jump uncond t ona y
w th n a oop The break statement causes you to ex t the oop mmed ate y The continue statement
abandons the current terat on and goes back to the top of the oop ready for the next terat on

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

Chapter 5 Dec s on and oop statements 73

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

break statement term nates the ent re oop

74Microsoft Visual C++/CLI Step by Step

Quick reference
To

Do this

Perform a one way test.

Use the if keyword fo owed by a test enc osed n paren


theses. You must enc ose the if body n braces f t con
ta ns more than one statement. For examp e:
if (n < 0)
{
Console::Write("The number ");
Console::Write(n);
Console::WriteLine(" is negative");
}

Perform a two way test.

Use an if else construct. For examp e:


if (n < 0)
{
Console::Write("Negative");
}
else
{
Console::Write("Not negative");
}

Perform a mu t way test.

Use an if else if construct. For examp e:


if (n < 0)
{
Console::Write("Negative");
}
else if (n == 0)
{
Console::Write("Zero");
}
else
{
Console::Write("Positive");
}

Test a s ng e express on aga nst a fin te set of constant


va ues.

Use the switch keyword fo owed by an ntegra expres


s on enc osed n parentheses. Define case branches for
each va ue you want to test aga nst, and define a defau t
branch for a other va ues. Use the break statement to
c ose a branch. For examp e:
int dayNumber; // 0=Sun, 1=Mon, etc.

switch (dayNumber)
{
case 0:
case 6:
Console::Write("Weekend");
break;
default:
Console::Write("Weekday");
break;
}

Perform terat on by us ng the while oop.

Use the while keyword fo owed by a test enc osed n


parentheses. For examp e:
int n = 10;
while (n >= 0)
{
Console::WriteLine(n);
n--;
}

Chapter 5 Dec s on and oop statements 75

CHAPTER 6

More about classes and objects


After completing this chapter, you will be able to:

Organ ze c asses nto header fi es and source fi es

Create objects

Define constructors to n t a ze an object

Define c ass-w de members by us ng the static keyword

Define re at onsh ps between objects n an app cat on

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

Organizing classes into header files and source files


Chapter 2 shows you how to define a s mp e c ass and mp ement a ts member funct ons n ne Lets
refresh your memory by cons der ng the fo ow ng c ass, wh ch represents a cred t card account
ref class CreditCardAccount
{
public:
void PrintStatement()
{
Console::Write("Credit card balance: ");
Console::WriteLine(currentBalance);
}
private:
double currentBalance;
};

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

78Microsoft Visual C++/CLI Step by Step

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.

Declaring a class in a header file


In th s exerc se, you w create a new app cat on and define a CreditCardAccount c ass n a header
fi e (You w mp ement the c ass n the exerc se that fo ows )
1. Start V sua Stud o 2012 and create a new CLR Conso e App cat on project named

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

center pane, c ck Header F e ( h)


4. Toward the bottom of the d a og box, n the Name box, type CreditCardAccount.h, and then

c ck Add
V sua Stud o creates an empty header fi e

Chapter 6 More about c asses and objects 79

5. Type the fo ow ng code n the header fi e to define the CreditCardAccount c ass


ref class CreditCardAccount
{
public:
void SetCreditLimit(double amount);
bool MakePurchase(double amount);
void MakeRepayment(double amount);
void PrintStatement();
long GetAccountNumber();
private:
long accountNumber;
double currentBalance;
double creditLimit;
};

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

80Microsoft Visual C++/CLI Step by Step

Implementing a class in a source file


In th s exerc se, you w

mp ement the CreditCardAccount c ass n a source fi e

1. Cont nue us ng the project from the prev ous exerc se


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

center pane, c ck C++ F e ( cpp)


4. Toward the bottom of the d a og box, n the Name box, type CreditCardAccount.cpp, and

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;
}

Chapter 6 More about c asses and objects 81

8. Imp ement the CreditCardAccount::MakePurchase member funct on as fo ows


bool CreditCardAccount::MakePurchase(double amount)
{
if (currentBalance + amount > creditLimit)
{
return false;
}
else
{
currentBalance += amount;
return true;
}
}

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

Th s funct on d sp ays nformat on about the current state of the account


11. Imp ement the GetAccountNumber member funct on as fo ows
long CreditCardAccount::GetAccountNumber()
{
return accountNumber;
}

12. Bu d the app cat on and fix any comp er errors

82Microsoft Visual C++/CLI Step by Step

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

//
//
//
//
//

ts pub c member funct ons

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

Chapter 6 More about c asses and objects 83

4. Bu d the app cat on and fix any comp er errors


5. Run the app cat on by press ng Ctr +F5

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

Initializing objects by using constructors


In th s sect on, you w

see how to define constructor funct ons for a c ass

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
};

84Microsoft Visual C++/CLI Step by Step

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.

Chapter 6 More about c asses and objects 85

3. Open Cred tCardAccount cpp and mp ement the constructor as fo ows


CreditCardAccount::CreditCardAccount(long number, double limit)
{
accountNumber = number;
creditLimit = limit;
currentBalance = 0.0;
}

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

Member initialization lists


Theres an a ternat ve syntax for n t a z ng data members n a constructor us ng a member n t a zat on st, as fo ows
CreditCardAccount::CreditCardAccount(long number, double limit)
: accountNumber(number), creditLimit (limit), currentBalance(0.0)
{
}

86Microsoft Visual C++/CLI Step by Step

The co on on the second ne s fo owed by a comma-separated st of data members For each


data member, an n t a va ue s prov ded n parentheses Observe that the body of the constructor s
now empty because we have noth ng e se to doth s s qu te norma
It s cons dered better pract ce to use a member n t a zat on st rather than n t a z ng members
n the constructor body There are a so some s tuat ons n wh ch you must use a member n t a zat on
st You see such an examp e n Chapter 8, Inher tance, when you de ve nto that subject

Defining class-wide members


The data members and member funct ons current y defined n the CreditCardAccount c ass are nstance members Each CreditCardAccount nstance has ts own accountNumber, currentBalance, and
creditLimit L kew se, when you nvoke member funct ons such as MakePurchase, MakeRepayment,
and PrintStatement, you must spec fy wh ch CreditCardAccount nstance youre us ng, as shown n the
fo ow ng figure

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

Chapter 6 More about c asses and objects 87

Lets see how to define c ass-w de data members and member funct ons

Defining class-wide data members


To define a c ass-w de data member, use the static keyword, as demonstrated n the fo ow ng code
ref class CreditCardAccount
{
private:
static int numberOfAccounts = 0;
// ... Other members, as before
};

// Declare class-wide data member

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:

88Microsoft Visual C++/CLI Step by Step

static int numberOfAccounts = 0;


// ... Other members, as before
};

3. Open Cred tCardAccount cpp and mod fy the CreditCardAccount constructor so that t ncre-

ments numberOfAccounts every t me a new CreditCardAccount object s created


CreditCardAccount::CreditCardAccount(long number, double limit)
{
accountNumber = number;
creditLimit = limit;
currentBalance = 0.0;
numberOfAccounts++;
Console::Write("This is account number ");
Console::WriteLine(numberOfAccounts);
}

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

Chapter 6 More about c asses and objects 89

Defining class-wide member functions


It can be dangerous to make data members pub c; preferab y, you want to g ve users access through
member funct ons To g ve access to a stat c data member, you can define a stat c member funct on
To define a c ass-w de member funct on, use the static keyword n the funct on dec arat on ke th s
ref class CreditCardAccount
{
public:
static int GetNumberOfAccounts();
// ... Other members, as before
};

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

90Microsoft Visual C++/CLI Step by Step

ref class CreditCardAccount


{
public:
static int GetNumberOfAccounts();
// ... Other members, as before
};

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

Accounts at var ous stages dur ng execut on


int n = CreditCardAccount::GetNumberOfAccounts();
Console::Write("Number of accounts initially: ");
Console::WriteLine(n);
Console::WriteLine("\nCreating 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();
n = CreditCardAccount::GetNumberOfAccounts();
Console::Write("\nNumber of accounts now: ");
Console::WriteLine(n);

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

Chapter 6 More about c asses and objects 91

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

he p you see when the constructor s ca ed

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

92Microsoft Visual C++/CLI Step by Step

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

The output from runn ng the app cat on appears as fo ows


Static constructor called
Number of accounts initially: 0

You can see from th s that the stat c constructor s ca ed mmed ate y before the first object s
created

Using constants in classes


You w often find that you need to represent constant va ues n your c asses, members whose va ue
cannot change as execut on proceeds These constants m ght be of two types

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

Using class-wide constants


A c ass-w de constant represents a va ue that s common to a nstances of a c ass For our Credit
Account examp e, suppose that th s k nd of cred t card account has a name, such as Super P at num
Card Th s name w app y to a cards of the same type, so t og ca y be ongs to the c ass rather
than each nstance Let us further suppose that the name assoc ated w th the card c ass snt go ng to
change Th s makes t a cand date for a c ass-w de constant
You can create a c ass-w de constant by us ng the literal keyword, as shown here
literal String ^name = "Super Platinum Card";

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

Chapter 6 More about c asses and objects 93

Lets see how to add the name to the CreditAccount c ass


1. Cont nue us ng the project from the prev ous exerc se
2. Open Cred tAccount h and add the dec arat on of a literal to the pub c sect on of the c ass

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

to the start of main, before you create any CreditCardAccount objects


Console::Write("Card name is ");
Console::WriteLine(CreditCardAccount::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

Literals and const


In standard C++, you wou d use a static const member to represent a c ass-w de constant
A though C++/CLI supports th s, constants dec ared n th s way are not recogn zed as comp et me constants f the c ass s accessed v a a #using statement Therefore, you are recommended
to use literal, because members dec ared n th s way behave as expected

Using instance constants


You can use the initonly keyword to mark a data member as per- nstance constant A data member
marked as initonly can have ts va ue set n the constructor for the c ass but cannot be mod fied after
that The fo ow ng short exerc se shows you how to use initonly n the CreditCardAccount c ass
1. Open Cred tAccount h and add initonly to the dec arat on of accountNumber
initonly long accountNumber;

2. Bu d the app cat on

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

94Microsoft Visual C++/CLI Step by Step

3. Open Cred tAccount cpp and try to ass gn a new va ue to accountNumber n one of the other

member funct ons, such as SetCreditLimit


4. Not ce that accountNumber s under ned n red, and f you hover over the var ab e name, a

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!

Defining object relationships


For the rema nder of th s chapter, you w see how to define re at onsh ps between objects n a C++/
CLI app cat on App cat ons typ ca y conta n many objects, and these objects commun cate w th one
another to ach eve the overa funct ona ty needed n the app cat on
To ustrate object re at onsh ps, you w add a new c ass named LoyaltyScheme to your cred t card
app cat on W th the LoyaltyScheme c ass, cred t card owners can co ect bonus po nts when they use
the r cred t card These po nts act as a reward for the customers oya use of the cred t card
When a CreditCardAccount object s first created, t doesnt have a LoyaltyScheme object The
LoyaltyScheme object s created when CreditCardAccount reaches 50 percent of ts cred t m t Subsequent y, every $10 spent us ng the cred t card w add one bonus po nt to the LoyaltyScheme object,
as ong as the account stays above the 50 percent mark
To ach eve th s funct ona ty, you w

comp ete the fo ow ng exerc ses

Define the LoyaltyScheme c ass

Imp ement the LoyaltyScheme c ass

Create and use LoyaltyScheme objects

Test the app cat on

Defining the LoyaltyScheme Class


In th s exerc se, you w

define the LoyaltyScheme c ass n a new header fi e named Loya tyScheme h

1. Cont nue us ng the project from the prev ous exerc se


2. On the Project menu, c ck Add New Item
3. In the Add New Item d a og box, se ect the temp ate Header F e ( h) In the Name box, type

LoyaltyScheme.h, and then c ck Add

Chapter 6 More about c asses and objects 95

4. Type the fo ow ng code n the header fi e to define the LoyaltyScheme c ass


ref class LoyaltyScheme
{
public:
LoyaltyScheme();
void EarnPointsOnAmount(double
void RedeemPoints(int points);
int GetPoints();
private:
int totalPoints;
};

// Constructor
amountSpent);
// Earn one point per $10 spent
// Redeem points
// Return the value of totalPoints
// Total points earned so far

5. Bu d the app cat on and fix any comp er errors

Implementing the LoyaltyScheme class


In th s exerc se, you w
Loya tyScheme cpp

mp ement the LoyaltyScheme c ass n a new source fi e named

1. Cont nue us ng the project from the prev ous exerc se


2. On the Project menu, c ck Add New Item
3. In the Add New Item d a og box, se ect the temp ate C++ F e ( cpp) In the Name box, type

LoyaltyScheme.cpp, and then c ck Add


V sua Stud o creates an empty source fi e
4. Add two #include statements at the beg nn ng of the fi e, as shown here
#include "stdafx.h"
#include "LoyaltyScheme.h"

5. Add the fo ow ng code to expose the System namespace


#using <mscorlib.dll>
using namespace System;

6. Imp ement the LoyaltyScheme constructor as fo ows


LoyaltyScheme::LoyaltyScheme()
{
Console::WriteLine("Congratulations, you now qualify for"
" bonus points");
totalPoints = 0;
}

96Microsoft Visual C++/CLI Step by Step

7. Imp ement the EarnPointsOnAmount member funct on as fo ows


void LoyaltyScheme::EarnPointsOnAmount(double amountSpent)
{
int points = (int)(amountSpent/10);
totalPoints += points;
Console::Write("New bonus points earned: ");
Console::WriteLine(points);
}

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;
}

10. Bu d the app cat on and fix any comp er errors

Creating and using LoyaltyScheme objects


In th s exerc se, you w
funct ona ty

extend the CreditCardAccount c ass to support the oya ty scheme

1. Cont nue us ng the project from the prev ous exerc se


2. Open Cred tCardAccount h At the beg nn ng of the fi e, add an #include d rect ve as fo ows
#include "LoyaltyScheme.h"

Th s makes t poss b e for you to use the LoyaltyScheme c ass n th s header fi e

Chapter 6 More about c asses and objects 97

3. Add a pr vate data member to the CreditCardAccount c ass as fo ows


LoyaltyScheme ^scheme;

// Handle to a LoyaltyScheme object

Th s hand e represents an assoc at on between a CreditCardAccount object and a


LoyaltyScheme object
4. Add a pub c member funct on to the CreditCardAccount c ass as fo ows
void RedeemLoyaltyPoints();

Th s funct on acts as a wrapper to the RedeemPoints funct on n the LoyaltyScheme c ass


When you want to redeem oya ty po nts, you ca RedeemLoyaltyPoints on your CreditCard
Account object Th s funct on ca s RedeemPoints on the under y ng LoyaltyScheme object to
do the work

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

statement n the constructor body


scheme = nullptr;

Th s statement sets the n t a va ue of the scheme hand e to nullptr Th s s a spec a va ue for a


hand e, nd cat ng that the hand e doesnt yet po nt to an object In our app cat on, the scheme
object wont be created unt the cred t card ba ance reaches 50 percent of the cred t m t

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

when the cred t card ba ance reaches 50 percent of the cred t m t


bool CreditCardAccount::MakePurchase(double amount)
{
if (currentBalance + amount > creditLimit)
{
return false;
}
else
{
currentBalance += amount;
// If current balance is 50% (or more) of credit limit...
if (currentBalance >= creditLimit / 2)

98Microsoft Visual C++/CLI Step by Step

{
// 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() );
}
}

Chapter 6 More about c asses and objects 99

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

Testing the application


In th s exerc se, you w mod fy the code n Cred tOrgan zer cpp to test the oya ty scheme funct ona ty
1. Cont nue us ng the project from the prev ous exerc se
2. Open Cred tOrgan zer cpp and mod fy the main funct on as fo ows
Console::WriteLine("Creating account object");
CreditCardAccount ^account1;
account1 = gcnew CreditCardAccount(12345, 2000);
Console::WriteLine("\nMaking a purchase (300)");
account1->MakePurchase(300);
Console::WriteLine("\nMaking a purchase (700)");
account1->MakePurchase(700);
Console::WriteLine("\nMaking a purchase (500)");
account1->MakePurchase(500);
Console::WriteLine("\nRedeeming points");
account1->RedeemLoyaltyPoints();

3. Bu d the app cat on and fix any comp er errors


4. Run the app cat on

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

100Microsoft Visual C++/CLI Step by Step

Quick reference
To

Do this

Define a c ass.

Add a header fi e to your project. Define the c ass n the


header fi e. For examp e:
ref class MyClass
{
public:
void MyFunction();
private:
int myData;
};

mp ement a c ass.

Add a source fi e to your project. n the source fi e, use a


#include statement to nc ude the header fi e that con
ta ns the c ass defin t on. Then mp ement the member
funct ons n the source fi e. For examp e:
#include "MyHeader.h"
void MyClass::MyFunction()
{
myData = myData * 2;
}

Prov de a constructor for a c ass.

Dec are the constructor n the header fi e, and mp ement


t n the source fi e. The constructor must have the same
name as the c ass and cannot return a va ue. However, a
constructor can take parameters. For examp e:
// Header file
ref class MyClass
{
public:
MyClass(int n);
...
};
// Source file
MyClass::MyClass(int n)
{
myData = n;
}

Chapter 6 More about c asses and objects 101

CHAPTER 7

Controlling object lifetimes


After comp et ng th s chapter, you w

be ab e to

Descr be how M crosoft NET memory management d ffers from trad t ona C++ memory
management

Prov de fina zers and destructors for your c asses

Create objects by us ng stack semant cs

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

The .NET approach to object lifetimes


Weve seen what happens at the start of an objects fe, but what happens when an object s no
onger requ red?
There are two th ngs that need to happen when an object comes to the end of ts fe

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

a ways be ava ab e as ong as there s at east one hand e to t

You cannot te when an objects memory w

be rec a med; th s s up to the garbage co ector


103

.NET garbage collection


The garbage co ect on mechan sm n the NET Framework s very soph st cated, but you dont
need to know much about the deta s to use C++/CLI In fact, ts des gned to work fine w thout any ntervent on from you at a However, f youre nterested to know a tt e more about
whats happen ng, read on
Memory for objects s a ocated from the managed heap, an area of memory that the NET
runt me uses to store dynam ca y a ocated objects Every a ocat on takes some space from the
heap, and ts poss b e that at some po nt heap memory w be exhausted, or (more ke y) there
wont be a p ece arge enough for the new a ocat on If a request for memory fa s, the garbage
co ector w be nvoked to see f there are any unreferenced objects whose memory can be
rec a med to free up some heap memory
The bas c process s as fo ows

F nd a the objects that are st a ve Th s means start ng w th hand es to objects n the


code Then, fo ow any hand es to other objects that they m ght have Th s repeats to
theend of each cha n of objects
When a the ve objects have been marked, assume that a the rest of memory s
garbage

Move the ve objects, compact ng them to create the max mum amount of free space

F x up the hand es to the ve objects so that they po nt to new ocat ons

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

104Microsoft Visual C++/CLI Step by Step

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

Destruction and finalization


Before we can start ook ng at code, ets ntroduce two new terms Finalization s what happens when
an objects memory s about to be rec a med and s under the contro of the garbage co ector You
can prov de code to be executed at th s po nt, n the form of a finalizer method on your c ass
But t m ght be that you know defin te y at some po nt n the code that you no onger need the
object, and you wou d ke t to t dy tse f up there and then For examp e, f you are work ng w th a
Customer object, you m ght want the object to save ts data back to the database when youve finshed w th t Th s s ca ed destruction, and you can prov de a destructor method n your c ass
W th C++/CLI, you can prov de code to be executed at both these po nts n an objects fecyc e, as
you w see n the fo ow ng sect ons

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

Chapter 7 Contro ng object fet mes 105

Here are three po nts you shou d note about destructors

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

A few points about finalizers


There are three th ngs that you shou d be aware of when us ng fina zers
F rst, dont define a fina zer for your c ass f you dont have anyth ng for t to do In most cases,
add ng an empty funct on to a c ass w have tt e effect, but that snt the case for fina zers If the
garbage co ector sees that your c ass mp ements a fina zer, t knows that t has to run th s before
rec a m ng objects of that type, and th s s ows down the co ect on process
Second, no guarantee s made as to the order n wh ch fina zers w run, wh ch can be prob emat c
f objects have dependenc es on one another Suppose that two objects, A and B, both have a fina zer, and that both of them update a data resource Both fina zers w be ca ed when the objects are
destroyed, but you cant know wh ch one w be ca ed first Th s means that you cant determ ne n
what order data w be wr tten to the data resource, wh ch cou d cause a prob em
And th rd, fina zers arent ca ed dur ng app cat on term nat on for objects that are st ve, such
as those be ng used by background threads or those created dur ng the execut on of a fina zer
A though a system resources w be freed up when the app cat on ex ts, objects that dont have
the r fina zers ca ed m ght not get a chance to c ean up proper y

106Microsoft Visual C++/CLI Step by Step

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

Implementing the destructor and finalizer for a class


In th s exerc se, you w

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

center pane, c ck Header F e ( h)


4. Toward the bottom of the d a og box, n the Name fie d, type MyClass.h, and then c ck 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. Open the header fi e and add the dec arat on for a c ass that has a constructor, a destructor, a

fina zer, and a s ng e work method, wh ch you w

ca to show that the object can be used

using namespace System;


ref class MyClass
{
String ^name;
public:
MyClass(String ^objectName);
~MyClass();
!MyClass();
void DoSomething();
};

//
//
//
//

constructor
destructor
finalizer
'work' method

6. Repeat steps 2 through 4, but th s t me add a source fi e ca ed MyClass.cpp to the project

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-

sage to show that has been ca ed


MyClass::MyClass(String ^objectName)
{
name = objectName;
Console::WriteLine("Constructor called for {0}", name);
}

Chapter 7 Contro ng object fet mes 107

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

has been used between creat on and destruct on


void MyClass::DoSomething()
{
Console::WriteLine("DoSomething called for {0}", name);
}

11. Bu d the project and fix any comp er errors

Using the finalizer


In th s exerc se you w

see how the fina zer for a c ass s ca ed

1. Cont nue us ng the project from the prev ous exerc se


2. Open L fet mes cpp and n the main method of the app cat on, create an object by us ng

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;
}

108Microsoft Visual C++/CLI Step by Step

3. Bu d and run the app cat on

Output s m ar to the fo ow ng appears


Constructor for m1
DoSomething called
End of Program
Finalizer called for m1

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

Using the destructor


In th s exerc se you w

see how the destructor for a c ass s ca ed

1. Cont nue us ng the project from the prev ous exerc se


2. Ed t the code so that you exp c t y de ete the object after us ng t Do th s by nsert ng a ca to

delete after the ca to DoSomething


MyClass ^m1 = gcnew MyClass("m1");
m1->DoSomething();
delete m1;

3. Bu d and run the app cat on

Output s m ar to the fo ow ng appears


Constructor called for m1
DoSomething called for m1
Destructor called for m1
End of Program

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

Chapter 7 Contro ng object fet mes 109

MyClass::~MyClass()
{
// Free up managed resources: this will be done anyway by the runtime
// Now call the finalizer to free unmanaged resources
this->!MyClass()
}

Objects and stack semantics


It m ght seem rather ted ous to have to create objects by us ng gcnew and then ca delete on the
hand es when you have fin shed us ng them After a , wasnt the dea of garbage co ect on supposed
to be that you d dnt have to keep track of your objects when you fin shed w th them?
It s mportant not to confuse the concept of an object t dy ng up after tse f w th the runt me
rec a m ng the objects memory; the two are ndependent of one another You m ght want to say what
an object does to t dy up when you have fin shed w th t but not rea y care when the garbage co ector dec des to rec a m ts memory In th s case, you wou d mp ement a destructor, wh ch you can then
ca by us ng delete

Traditional C++ object creation and destruction


Trad t ona C++ objects can a so have destructors and be dynam ca y created and destroyed n a
manner very s m ar to the one to wh ch you have become accustomed They use new nstead of
gcnew, but the mechan sm s very s m ar
There s, however, another way by wh ch objects can be created n standard C++, and that s to
create them on the stack as oca objects, such as ustrated n the fo ow ng
MyClass m("m3");
m.DoSomething();

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

110Microsoft Visual C++/CLI Step by Step

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

Creating objects with stack semantics


In C++/CLI, you can create your objects n the same way, as you w

see n the next exerc se

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

3. Bu d and run the app cat on

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.

Chapter 7 Contro ng object fet mes 111

The Resource Acquisition Is Initialization idiom


Resource Acqu s t on Is In t a zat on (RAII) s an awkward phrase that s used to descr be a very
common programm ng sty e n C++, one that s usefu n many c rcumstances You w find that
you often want an object to do someth ng when you create t and then do a match ng act on
when the object d es For examp e, open a fi e and then ensure that t s c osed, or read data
from a database and then ensure that t s updated
In C++, you can pa r up these act ons by perform ng the act on n a constructor and then
perform ng the match ng act on n the destructor In th s way, you can be certa n that the
match ng act on w be performed w thout you hav ng to remember to do t
Heres an examp e suppose that you want to change the cursor to an hourg ass before startng a ong-runn ng operat on and then revert to the arrow cursor upon comp et on You cou d
code t up ke th s
void DoLongOperation()
{
SetCursorToHourglass();
// Lots of complex code...
SetCursorToArrow();
}

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

You can now recode DoLongOperation to match the fo ow ng


void DoLongOperation()
{
BusyCursorHelper bch();
// Lots of complex code...
}

112Microsoft Visual C++/CLI Step by Step

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

Do I need a copy constructor?


Standard C++ makes heavy use of copy constructors because they are needed to support
proper memory management Referr ng to ref objects through hand es, coup ed w th garbage
co ect on, means that you dont need copy constructors near y as often n C++/CLI
In standard C++ the comp er w g ve you a defau t copy constructor f you do not prov de one Th s s not the case n C++/CLI, so f you want to prov de copy construct on for your
c asses, you w need to wr te a copy constructor

Lets start by ana yz ng what happens n the fo ow ng p ece of code


ref class MyClass
{
int value;
String ^str;
public:
MyClass(int v, String ^s) : value(v), str(s) {}
int getValue() { return value; }
String ^getString() { return str; }
};
int main(array<System::String ^> ^args)
{
Console::WriteLine("Copy Construction");

Chapter 7 Contro ng object fet mes 113

MyClass ^one = gcnew MyClass(3, "abc");


MyClass ^two = one;

Console::WriteLine("Value: {0}, str: {1}", two->getValue(), two->getString());


return 0;

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.

114Microsoft Visual C++/CLI Step by Step

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?

referr ng to the same object n memory

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

Chapter 7 Contro ng object fet mes 115

3. Imp ement the ma n funct on to create and use MyClass objects


int main(array<System::String ^> ^args)
{
Console::WriteLine("Copy Construction");
MyClass ^one = gcnew MyClass(3, "abc");
MyClass ^two = one;
Console::WriteLine("Value: {0}, str: {1}", two->getValue(), two->getString());
MyClass three = *one;
three.setValue(4);
Console::WriteLine("Value of one: {0}", one->getValue());
Console::WriteLine("Value of three: {0}", three.getValue());
return 0;
}

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

Relating objects with stack semantics


It s common for objects to be composed of other objects For examp e, a Person m ght have an
Address, or a Rectangle m ght be composed of two Points Cons der the Rectangle as an examp e
Because the Points are part of the Rectangle, t s reasonab e to expect that when a Rectangle object
s destroyed, ts Points are destroyed, as we If you dec are the objects by us ng stack semant cs, you
can eas y ensure that th s happens
In th s exerc se, you w

see how to compose objects so that they are destroyed correct y

1. Create a new CLR Conso e App cat on project w th a su tab e name


2. Add a header fi e ca ed Geometry h to the project
3. Ed t the header fi e to define two c asses Rectangle and Point Note that a Rectangle s com-

posed of two Points


using namespace System;
ref class Point
{
public:
Point();
~Point();
};

116Microsoft Visual C++/CLI Step by Step

ref class Rectangle


{
Point p1, p2;
public:
Rectangle();
~Rectangle();
};

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");
}

5. Ed t main to create a Rectangle object by us ng stack semant cs Remember to add a #include

for Geometry.h, as shown n the fo ow ng


#include "Geometry.h"
int main(array<System::String^>^ args)
{
Rectangle r;
Console::WriteLine();
Console::WriteLine("End of program");
Console::WriteLine();
return 0;
}

Chapter 7 Contro ng object fet mes 117

6. Bu d and run the app cat on

You shou d see output s m ar to the fo ow ng


Point constructor called
Point constructor called
Rectangle constructor called
End of program
Rectangle destructor called
Point destructor called
Point 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();

// This won't work

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.

When to use handles?


If you want a c ass to conta n another objectas n the preced ng Rectangle/Point exerc seyou have
a cho ce of how to represent the composed object You cou d use an object, as you d d n the exerc se, or you cou d use a hand e to an object, as n the fo ow ng code
ref class Rectangle
{
Point ^p1;
Point ^p2;
...
};

What s the d fference between these two, and why m ght you choose one over the other?

118Microsoft Visual C++/CLI Step by Step

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?

Is the conta ned object shared w th anyone e se?

Cou d you swap the conta ned object for another one?

Can the conta ned object ve on after ts conta ner?

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

Define a destructor for a c ass.

Add a member funct on that has the same name as the


c ass but prefixed w th a t de (~). For examp e:
MyClass::~MyClass()
{
...
}

Define a fina zer for a c ass.

Add a member funct on that has the same name as


the c ass but prefixed w th an exc amat on mark (!). For
examp e:
MyClass::!MyClass()
{
...
}

Destroy a dynam ca y created object.

Ca delete on the hand e to the object. For examp e:


MyClass ^m = gcnew MyClass();
...
delete m;

Chapter 7 Contro ng object fet mes 119

CHAPTER 8

Inheritance
After comp et ng th s chapter, you w

be ab e to

Descr be the mportance of nher tance n object-or ented programm ng

Define a base c ass

Define a der ved c ass

Access base-c ass members from the der ved c ass

Use the virtual keyword to ach eve po ymorph sm

Define abstract c asses and abstract methods

Define sea ed c asses

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

C++ tends to use the term base and derived c asses

Java uses superclass and subclass

Other anguages m ght use parent and child

Us ng the correct terms for your anguage s, of course, not as mportant as gett ng the re at onsh ps correct

Inheritance and code reuse


Suppose that you are des gn ng a Vehicle c ass and some c asses that der ve from t You w put the
th ngs that are common to a veh c es n the Vehicle c ass, us ng the der ved c asses to mp ement
those features that make them un que
The der ved c asses nher t the funct ona ty of the Vehicle c ass They have to; otherw se, they
wou d not be Vehicles Th s means that after you have mp emented funct ona ty n the Vehicle c ass,
you dont have to dup cate t n the der ved c asses
It s very mportant to understand that code reuse s not the ma n reason for nher tance A though
t s usefu , the ma n reason why you want to use nher tance s to define re at onsh ps between types
If you happen to a so ga n the benefit of code reuse, th s s a bonus If you use nher tance so e y for
code reuse, you r sk bu d ng ncorrect nher tance mode s

122Microsoft Visual C++/CLI Step by Step

Designing an inheritance hierarchy


Before you start wr t ng any code to use nher tance n C++, you shou d spend some t me des gn ng
the nher tance h erarchy Ident fy c asses that have common behav or, and cons der whether these
c asses wou d benefit from us ng nher tance
In th s chapter, you w define and mp ement an nher tance h erarchy represent ng d fferent types
of bank accounts The fo ow ng ustrat on shows how the c asses w be arranged n the nher tance
h erarchy

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

Chapter 8 nher tance 123

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

Defining a base class


When you define a base c ass, you can start t by defin ng the common member funct ons that w be
requ red by a the der ved c asses After you have defined these member funct ons, add data members to support the r mp ementat on Then, prov de one or more constructors to n t a ze these data
members

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

center pane, c ck Header F e ( h)


4. Toward the bottom of the d a og box, n the Name box, type BankAccount.h, and then c ck

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;

124Microsoft Visual C++/CLI Step by Step

ref class BankAccount


{
public:
BankAccount(String ^holder);
void Credit(double amount);
void Debit(double amount);
double GetBalance();
private:
String ^accountHolder;
double balance;
};

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.

Working with floating-point values


In th s s mp e examp e, the code uses a double to ho d the ba ance A though th s s fine n
th s case because were not actua y concerned that the ba ance s accurate, you wou d never
use a double n any p ace where a float ng-po nt va ue needs to be exact, such as n bank ng
ca cu at ons
The reason for th s s that ar thmet c on float and double va ues s subject to round ng errors
Because of the way n wh ch these types are mp emented, some va ues cannot be represented
exact y It s s m ar to the way n wh ch 1/3 cannot be exact y represented as a dec ma ( t s a
repeat ng va ue, 0 33333, wh ch never term nates) Th s means that ar thmet c on such va ues
ends up accumu at ng errors due to the approx mat ons nvo ved These can be very sma , but
n some app cat ons they are s gn ficant
Not on y m ght va ues be nexact, but because of th s, t m ght not be poss b e to compare
va ues exact y Two var ab es that ought to have the same va ue m ght be s ght y d fferent
because of accumu ated errors dur ng the r ca cu at on
In more ser ous code, you shou d use the System::Decimal type, wh ch prov des an exact representat on of float ng-po nt va ues and s not subject to round ng errors The downs de s that
operat ons are ess effic ent than those us ng float or double

Chapter 8 nher tance 125

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.

8. Bu d the app cat on and fix any comp er errors

Defining a derived class


To define a der ved c ass n C++/CLI, use the fo ow ng syntax
ref class MyDerivedClass : MyBaseClass
{
...
};

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

126Microsoft Visual C++/CLI Step by Step

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.

Inheritance and System::Object


In NET, every c ass der ves u t mate y from the System::Object c ass If you dont spec fy a base
c ass, the c ass you create w mp c t y have : System::Object added to ts dec arat on Th s
means that every object you create s a System::Object, and a so that a c asses nher t the
common funct ona ty that Object prov des, such as the ToString funct on

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

Chapter 8 nher tance 127

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

128Microsoft Visual C++/CLI Step by Step

private:

static double interestRate;
};

8. Add a source fi e to the project named SavingsAccount.cpp


9. Add the fo ow ng code to the fi e to mp ement the SavingsAccount c ass
#include "stdafx.h"
#include "SavingsAccount.h"
SavingsAccount::SavingsAccount(String ^holder) : BankAccount(holder) { }
void SavingsAccount::SetInterestRate(double rate)
{

interestRate = rate;
}
double SavingsAccount::GetInterestRate()
{

return interestRate;
}

10. Bu d the app cat on and fix any comp er errors

Creating derived class objects


In th s exerc se, you w

see how to create and use objects of a der ved c ass

1. Cont nue us ng the project from the prev ous exerc se


2. Open B gBank cpp and add #includes for the CurrentAccount and SavingsAccount header fi es
#include "CurrentAccount.h"
#include "SavingsAccount.h"

Note There is no need to explicitly write #include BankAccount.h because this


header file is already included in CurrentAccount.h and SavingsAccount.h.
3. De ete the He o Wor d ne from main Add code to create a CurrentAccount object and

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

Chapter 8 nher tance 129

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

5. Bu d and run the app cat on

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

You shou d see output s m ar to th s


Balance: 100
Overdraft: 2000
Interest Rate: 2.5

Concrete and abstract classes


When you define an nher tance h erarchy, the base c ass acts as a repos tory for the common member funct ons and data members requ red by der ved c asses However, the base c ass often doesnt
represent a rea object
Cons der the bank account examp e weve been deve op ng n th s chapter When you wa k nto a
bank to open an account, you have to spec fy what type of account you want (check ng account or
sav ngs account) You cant just open a bank account
In s m ar fash on, when programm ng, you shou d prevent gener c BankAccount objects from
be ng created You shou d a ow on y der ved c asses such as CurrentAccount and SavingsAccount to
be nstant ated To accomp sh th s n C++/CLI, dec are the BankAccount c ass as an abstract c ass, as
demonstrated n the fo ow ng
ref class BankAccount abstract
{
// ... Class body, as before
};

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

1. Cont nue us ng the project from the prev ous exerc se


2. Open BankAccount h and change the BankAccount c ass defin t on by add ng the abstract

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

Overriding member functions


When you define a base c ass, you must cons der whether der ved c asses w need to overr de any
of your base-c ass member funct ons For each member funct on n the base c ass, there are three
poss b t es

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

// This function cannot be overridden


// Neither can this one

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;
...
};

// This function can be overridden

Chapter 8 nher tance 131

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

132Microsoft Visual C++/CLI Step by Step

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;

3. Open BankAccount cpp and mp ement the ToString funct on as fo ows


String ^BankAccount::ToString()
{
String ^result = gcnew String("Account holder: ");
result = String::Concat(result, accountHolder);
result = String::Concat(result, ", Balance: ");
result = String::Concat(result, balance.ToString());
return result;
}

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;

Chapter 8 nher tance 133

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

n CurrentAccount cpp, mp ement the CanDebit funct on as fo ows

bool CurrentAccount::CanDebit(double amount)


{
return (amount <= GetBalance() + overdraftLimit);
}

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;

Chapter 8 nher tance 135

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";
}

136Microsoft Visual C++/CLI Step by Step

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)

Defining sealed classes


In C++/CLI, you can define a c ass as sealed, wh ch means that the c ass cannot be used as a base c ass
Defin ng a c ass as sea ed s usefu f t performs operat ons that you dont want custom zed n der ved
c asses, but t s a so usefu n another, ess obv ous way If a c ass s sea ed, the comp er knows that
t w not have any der ved c asses Because th s means that there w be no ca s to v rtua funct ons,
the comp er m ght be ab e to generate more effic ent code
To mark a c ass as sea ed, use the sealed keyword n the c ass defin t on as fo ows
ref class MyClass sealed
{
// ... Class body, as before
};

Abstract and sealed


It m ght appear at first s ght that abstract and sealed are oppos tes one means that a c ass has to have
der ved c asses to be usefu , whereas the other means that you cant der ve c asses It s, however, poss b e to use abstract and sealed together on a c ass
Suppose that you have a c ass that on y conta ns stat c (c ass- eve ) members It wou d make sense
to say that you do not want objects of th s type, because there are no object- eve funct ons Mak ng
the c ass abstract prevents nstant at on In add t on, you m ght want to prevent anyone from add ng
extra funct ons to your c ass, wh ch sealed does

Note You can specify the sealed and abstract modifiers in any order.

Chapter 8 nher tance 137

Defining and using interfaces


Interfaces are an mportant programm ng construct n NET; therefore, you need to be ab e to use
them n C++/CLI You have a ready earned about pure v rtua funct ons, wh ch are spec fied n a base
c ass but mp emented by a der ved c ass Imag ne that you have a c ass that on y conta ns pure v rtua
funct ons, such as the fo ow ng
ref class XmlWriter
{
public:
virtual void ReadFromXmlFile(String ^filename) = 0;
virtual void WriteToXmlFile(String ^filename) = 0;
};

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
}
};

138Microsoft Visual C++/CLI Step by Step

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 conta n mp ementat on and data members; an nterface cannot

A members of an nterface are public and abstract by defin t on

Interface names shou d start w th an I (cap ta ) by convent on

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

Define an abstract base c ass.

Use the abstract keyword n the c ass defin t on. For ex


amp e:
ref class MyBase abstract
{
...
};

Define a der ved c ass.

n the der ved c ass defin t on, use a co on fo owed by


the name of the base c ass. For examp e:
ref class MyDerived : MyBase
{
...
};

Construct der ved objects.

n the der ved c ass constructor, use a member n t a za


t on st to ca the base c ass constructor. For examp e:
MyDerived::MyDerived(int bdata, int ddata)
: MyBase(bdata), derivedData(ddata)
{
...
}

Chapter 8 nher tance 139

PAR T I I

Microsoft .NET
programming basics
CHAPTER 9

Va ue types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

143

CHAPTER 10

Operator over oad ng

159

CHAPTER 11

Except on hand ng . . . . . . . . . . . . . . . . . . . . . . . . . .

175

CHAPTER 12

Arrays and co ect ons

197

CHAPTER 13

Propert es . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

229

CHAPTER 14

De egates and events . . . . . . . . . . . . . . . . . . . . . . . .

245

CHAPTER 15

The NET Framework c ass brary

263


141

CHAPTER 9

Value types
After comp et ng th s chapter, you w

be ab e to

D st ngu sh between reference and va ue types

Work w th structures

Work w th enumerat ons

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

Reference types and value types


Lets summar ze what youve earned about c asses so far C asses are known as reference types because you a ways access objects by us ng reference var ab es, known as handles Cons der the fo owng ne of code
MyClass ^pc = gcnew MyClass();

In th s examp e, pc s a reference var ab e by wh ch we can refer to the MyClass object created by


the gcnew operator Access ng objects by us ng references n th s way makes t poss b e for the NET
garbage-co ect on mechan sm to rec a m the resources used by an object when there are no onger
any references to t Th s feature of NET makes for effic ent memory usage and means that you wont
suffer from one of the trad t ona prob ems of C++ app cat ons memory eaks


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

Creating and using a simple struct


The fo ow ng exerc se shows how to create a structure represent ng a po nt w th X and Y coord nates,
how to create nstances of the structure, and how to use the nstances n code

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

146Microsoft Visual C++/CLI Step by Step

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

5. Comp e and run the app cat on

At th s po nt, you shou d see the output p1 x s 10

Investigating the structure


In th s exerc se, you w run the app cat on under contro of the debugger so that you can ook at the
structure of the va ue type you have created
1. If you c osed the Structs project, open t aga n and open the source fi e Structs cpp
2. Insert a debug breakpo nt by c ck ng n the gray border to the eft of the code C ck next to

the dec arat on of p1


A red dot appears n the border, as

ustrated n the screen shot that fo ows

Chapter 9 Va ue types 147

3. 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 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

148Microsoft Visual C++/CLI Step by 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

The differences between structures and classes


Structures and c asses have severa fundamenta d fferences

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

Implementing constructors for a structure


In th s next exerc se, you w
zed on creat on

add a constructor to the Point structure so that nstances can be n t a -

1. Cont nue us ng the project from the prev ous exerc se


2. Add a constructor to your Point structure so that the code ooks ke th s
value struct Point
{
int x, y;
Point(int xVal, int yVal) { x = xVal; y = yVal; }
}

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.

Chapter 9 Va ue types 149

3. You can now add extra code to your main funct on to create n t a zed Points
Point p2(10,20);

// use the second constructor to set x


// to 10 and y to 20
Console::WriteLine("p2.x is {0}", p2.x);

4. Bu d and run the app cat on Check that the resu t s what you expect

Using one structure within another


Its poss b eand often usefu to use one structure w th n another Imag ne that you have a structure named Person for descr b ng a person The structure conta ns the name and date of b rth, among
other data You cou d use separate fie ds for each tem, but you cou d a so make the date entr es nto
another structure and refer to t ns de Person Heres an examp e
// A Date structure containing day, month and year
value struct Date
{
int dd, mm, yyyy;
};
// A Person structure containing a Date member
value struct Person
{
String ^name;
Date DOB;
};

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

defin t ons for Date and Person


3. In the main funct on, create a Person object Remember that you dont use gcnew, because

structures are va ue types


// Create a Person
Person p1;

4. F

n the va ues for the fie ds

// Fill in the name


p1.name = "Fred";
p1.DOB.dd = 10;
p1.DOB.mm = 3;
p1.DOB.yyyy = 1960;

150Microsoft Visual C++/CLI Step by Step

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

Note Use of an aggregate initializer is an alternative to using a constructor and can


be handy where theres no checking to be done on the data.
6. If you dec de that the date of b rth s wrong, you can s mp y create a new Date and copy t

nto the Person object, such as n the fo ow ng


// Create a new Date
Date newDOB = {1, 4, 1955};
p1.DOB = newDOB;

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

The members of p1 d sp ay n red as each va ue changes

Chapter 9 Va ue types 151

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.

152Microsoft Visual C++/CLI Step by Step

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

Creating and using an enumeration


In the fo ow ng exerc se, you w create an enumerat on to ho d va ues represent ng the days of the
week and then use t n an app cat on
1. Create a new CLR Conso e App cat on project named Enums
2. At the top of the Enums cpp fi e, mmed ate y be ow the using namespace System; ne, add the

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.

Chapter 9 Va ue types 153

4. Try pr nt ng out the va ue of the WeekDay object ke th s


Console::WriteLine("Value of w is {0}", (int)w);

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

5. It wou d be good to be ab e to pr nt out the symbo assoc ated w th the enumerat on as we

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

Format needs to be nformed as to the type of the enumerat on, wh ch you do t by us ng


Enum::typeid and the va ue tse f The G nd cates the format for the convers on th s s genera format, wh ch means a str ng

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.

More about enumerations


Even though the va ue g ven to an enumerat on s an nteger, theres no mp c t convers on between
enumerat ons and ntegers If you cons der the fo ow ng nes of code, you understand why
//** This code won't compile! **//
// '1' would mean Tuesday
w = 1;
// What would '8' mean?
w = 8;

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

154Microsoft Visual C++/CLI Step by Step

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
};

Using enumerations in applications


In th s exerc se, you see how to use an enumerat on to contro app cat on execut on by us ng t n a
sw tch statement
1. Cont nue us ng the project from the prev ous exerc se If youve c osed t, on the F e menu,

c ck Open So ut on to open the project aga n


2. After the WriteLine statements, add the fo ow ng switch statement code
// Switch on the weekday
switch(w)
{
case WeekDay::Monday:
Console::WriteLine("It's
break;
case WeekDay::Tuesday:
Console::WriteLine("It's
break;
case WeekDay::Wednesday:
Console::WriteLine("It's
break;
default:
Console::WriteLine("It's
}

a Monday!");

a Tuesday!");

a Wednesday!");

some other day...");

Chapter 9 Va ue types 155

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

Using memory efficiently


By defau t, an enum s an int, and therefore, enumerat ons are 32 b ts n s ze, wh ch g ves you a range
of va ues of 2,147,483,648 through 2,147,483,647 If youre go ng to use on y sma va ues for enumerat on members, memory w be wasted f each var ab e takes up 32 b ts For th s reason, ts poss b e
to base an enumerat on on any nteger type In the case of our WeekDay examp e, a our va ues can
qu te happ y fit nto 1 byte Thus, you cou d base the enum on a char, as shown here
// WeekDay variables are one byte in size
public enum class WeekDay : char
{
Monday = 1, Tuesday, Wednesday, Thursday, Friday,
Saturday, Sunday
};

Quick reference
To

Do this

Create a structure.

Use value struct, fo owed by the name of the structure


and the body n braces, fo owed by a sem co on. For
examp e:
value struct Point3D
{
int x, y, z;
};

n t a ze structure members.

Create a constructor, wh ch s a funct on that has the


same name as the structure. For examp e:
value struct Point3D
{
int x, y, z;
Point3D(int xVal, int yVal, int zVal)
{
x=xVal;
y=yVal;
z=zVal;
}
};

You can a so use an aggregate n t a zer:


Point3D p1 = { 10, 20, 30 };

Access structure members.

Use the dot notat on. For examp e:


p1.x = 10;
myPerson.DOB.dd = 20;

156Microsoft Visual C++/CLI Step by Step

CHAPTER 10

Operator overloading
After comp et ng th s chapter, you w

be ab e to

Descr be what operator over oad ng s

Dec de wh ch c asses shou d support operator over oad ng

Recogn ze what you can and cant over oad

Descr be gu de nes for prov d ng over oaded operators

Exp a n how to mp ement operator over oads

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!

What is operator overloading?


Chapter 3, Var ab es and operators, ntroduces the operators prov ded by the C++ anguage The
prob em s that those operators work on y w th the bu t- n types, and now, youre start ng to use
c asses and structures to define your own data types Th s means that f you want to add or compare
objects of types that youve created, you cant use the + and == operators because the comp er
doesnt know how to app y them to your objects


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

Overloading operators in managed types


Lets start by add ng operator over oad ng to va ue types and then move on to reference types You
a ready know that va ue types are the types most ke y to need operator over oad ng

Overloading arithmetic operators


In th s exerc se, you see how to mp ement operators n a va ue type The exerc se a so ntroduces
many of the techn ques you need to use when add ng operator over oad ng to your own types
1. Start M crosoft V sua Stud o 2012 and create a new CLR Conso e App cat on project named

Overload
2. At the top of the Over oad cpp fi e, mmed ate y be ow the using namespace System; ne, add

the fo ow ng struct defin t on


// The IntVal struct definition
value struct IntVal
{
private:
int value;
public:
IntVal(int v) : value(v) { }
int getVal() { return value; }
};

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

Chapter 10 Operator over oad ng 161

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;

// will get zero value

Because va ue types a ways have a defau t constructor, three w

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,

p ac ng t after the getVal funct on


IntVal operator+(IntVal rhs)
{
IntVal result(value + rhs.value);
return result;
}

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

t s actua y ca ng the funct on you define, ke th s


one.operator+(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.

Using static operator overloads


Becasue IntVal s bas ca y just an int wrapped up n a struct, t wou d seem reasonab e to want to
doth s
three = one + 2;

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;

Chapter 10 Operator over oad ng 163

3. Add a stat c vers on of operator+ to IntVal


static IntVal operator+(int lhs, IntVal rhs) {
IntVal result(lhs + rhs.value);
return result;
}

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 s an examp e of a conversion operator, a funct on that d rects the comp er how to


convert to and from a type Th s funct on nstructs the comp er how to get from an int to
an IntVal by creat ng an IntVal and n t a z ng t w th the int In effect, you are say ng to the
comp er, If you see an int but you want an IntVal, heres what to do If you dont have such a
convers on operator, the comp er wont be ab e to perform the convers on

Conversions and C++/CLI


Standard C++ embod es the concept of converting constructors If you defined IntVal as a
standard C++ structure, the constructor that takes an int wou d a ow the comp er to mp c t y
convert ints to IntVals wherever t s needed M crosoft dec ded to d sa ow th s mp c t convers on n C++/CLI, so even f you have a su tab e constructor, you have to prov de a convers on
operator to s gna the comp er that t can perform the convers on

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

2. Ed t the code n main to test a the poss b e opt ons


three = one + two;
Console::WriteLine("three is {0}", three.value);
three = one + 2;
Console::WriteLine("three is {0}", three.value);
three = 2 + one;
Console::WriteLine("three is {0}", three.value);

You can ver fy that the convers on s occurr ng by us ng the debugger


3. P ace a breakpo nt n the code by c ck ng n the gray marg n to the eft of the three = 2 +
one ne
4. Press F5 to start the debugg ng sess on

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

Overloading compound assignment operators


C++ has a number of compound ass gnment operators, such as += and =, w th wh ch you
can use x += 2 as shorthand for x = x + 2 In standard C++, they are cons dered comp ete y
separate operators; you dont get += just because you have over oaded the + and =
operators
In C++/CLI, the compound ass gnment operators are synthes zed for you Th s means that
x+= 2 s rewr tten as x = x + 2 so that your over oaded + operator can be used

Chapter 10 Operator over oad ng 165

1. Us ng the same project as n the prev ous exerc ses, find the operator+ funct on n your code

and add the fo ow ng funct on after t


static bool operator==(IntVal lhs, IntVal rhs) {
return lhs.value == rhs.value;
}

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

6. Bu d and run the app cat on to ensure that a

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

168Microsoft Visual C++/CLI Step by Step

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

Chapter 10 Operator over oad ng 169

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

mp ement Equals for the IntVal structure

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

170Microsoft Visual C++/CLI Step by Step

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

Points about Equals


System::ValueType, the base type for a structures, mp ements a vers on of Equals Th s means
that you dont actua y need to prov de your own, but you m ght want to because the nher ted
vers on can be very s ow It uses a feature ca ed reflection to exam ne objects at run t me, find
the r data members, and compare them If you find that the performance of Equals s a concern, you now know how to prov de your own vers on
If you do overr de Equals, you shou d a so cons der overr d ng the GetHashCode funct on,
as we A hashcode s an nteger va ue that represents an object It s used when stor ng data n
d ct onar es If two objects are equa , they shou d have the same hashcode Ca cu at ng hashcodes s beyond the scope of th s book

Implementing increment and decrement


As a fina examp e, th s sect on shows you how to over oad the ncrement and decrement operators
(++ and ) As s d scussed n Chapter 3, the bu t- n ++ and operators are used to ncrement and
decrement the va ue of nteger var ab es You can over oad them for your own types, and t makes
sense to use them wherever you have the dea of ncrement ng or decrement ng For examp e, f
you had a Date type, you cou d over oad ++ and to add or subtract a day from the current date,
adjust ng the month and year as appropr ate
You a so saw how these operators can be p aced before or after the var ab e If p aced before
(ca ed pre-increment and pre-decrement), the va ue w be adjusted before the var ab e s used n
the express on If p aced after (post-increment and post-decrement), the or g na va ue s used n the
express on, and the va ue adjusted after t has been used
In standard C++, you wou d prov de two operator over oads each for ++ and , one each for the
pre- ncrement and post- ncrement cases In C++/CLI, you mp ement the over oad of each operator as
a s ng e stat c member, and th s does for both cases
1. Cont nue w th the same project Add the fo ow ng method to the IntVal structure
static IntVal operator++(IntVal i)
{
i.value++;
return i;
}

Chapter 10 Operator over oad ng 171

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

3. Bu d and run the app cat on

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

be s mp e to emp oy decrement n the

Operators and reference types


Imp ement ng operators for reference types s very s m ar to mp ement ng them for va ue types, the
ma n d fference be ng that you need to dea w th hand es to objects As an examp e, here s part of
the IntVal structure, re- mp emented as a ref type rather than a value type
ref struct IntVal
{
int value;
IntVal(int v) : value(v) { }
static operator IntVal^(int v)
{
return gcnew IntVal(v);
}
static IntVal^ operator+(IntVal ^lhs, IntVal ^rhs) {
IntVal^ result = gcnew IntVal(lhs->value + rhs->value);
return result;
}
};

172Microsoft Visual C++/CLI Step by Step

int main(array<System::String ^> ^args)


{
IntVal ^one = gcnew IntVal(1);
IntVal ^two = gcnew IntVal(2);
IntVal ^three = one + two;
Console::WriteLine("Three is {0}", three->value);
IntVal ^anotherThree = 1 + two;
Console::WriteLine("anotherThree is {0}", anotherThree->value);
return 0;
}

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

Guidelines for providing overloaded operators


The most mportant gu de ne to keep n m nd s that overloaded operators must make intuitive sense
for a class For nstance, f you have a String c ass, us ng + to concatenate the Strings s pretty ntu t ve
You m ght get some agreement that , as n s2 s1, wou d mean ook for s1 w th n s2, and f you find
t, remove t However, what cou d the * operator mean when app ed to two Strings? Theres no obv ous mean ng, and youre on y go ng to confuse peop e f you prov de t So, ensure that the operators
you prov de for your types are the ones that peop e expect to find
The second gu de ne s operator usage must be consistent In other words, f you over oad ==,
ensure that you over oad !=, as we The same goes for < and >, ++ and , and so on
The th rd gu de ne s dont overload obscure operators or ones that change the semantics of the
language Operators such as the comma are obscure, and few peop e know how they work, so t snt
a good dea to over oad them Other operators, such as the og ca AND and OR operators (&& and
), can cause prob ems In ear er chapters, you earned about the if statement and how express ons
jo ned by && and are on y eva uated f necessary As a resu t, some express ons n an if statement
m ght never be eva uated If you over oad the AND and OR operators, the who e of the express on w
have to be eva uated, wh ch changes the way the if works

Chapter 10 Operator over oad ng 173

Quick reference
To

Do this

Over oad operators.

mp ement a funct on hav ng the name operator w th the


operator symbo appended. For examp e:
IntVal operator+(IntVal other)
{
...
}

Over oad operators for va ue types.

Pass arguments and return va ues as va ue objects.

Over oad operators for reference types.

Pass arguments and return va ues as hand es.

mp ement equa ty tests.

Over oad == and != and prov de an over oad of Equa s


for the benefit of other .NET anguages.

174Microsoft Visual C++/CLI Step by Step

CHAPTER 11

Exception handling
After comp et ng th s chapter, you w

be ab e to

Exp a n what except ons are

Recogn ze the d fferent types of except ons that can be used n C++/CLI

Descr be how to generate except ons

Exp a n how to hand e except ons

Create your own except on c asses

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

What are exceptions?


Except ons are an error-hand ng mechan sm emp oyed extens ve y n C++ and severa other modern
programm ng anguages Trad t ona y, error and status nformat on s passed around by us ng funct on return va ues and parameters, as demonstrated n the fo ow ng
// Pass status back as return value
bool bOK = doSomething();
// Pass status back in a parameter
int status;
doSomething(arg1, arg2, &status);

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

You cant force the programmer to do anyth ng about the error

The programmer doesnt even have to check the error code

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

The call stack and exceptions


At any po nt n an app cat on, the ca stack ho ds nformat on about wh ch funct ons have
been ca ed to get to the current po nt The ca stack s used n three ma n ways by app cat ons dur ng execut on to contro ca ng and return ng from funct ons, by the debugger, and
dur ng except on hand ng
The hand er for an except on can occur n the rout ne n wh ch the except on was thrown It
can a so occur n any rout ne above t n the ca stack, and, at run t me, each rout ne n the ca
stack s checked to see f t mp ements a su tab e hand er If noth ng su tab e has been found
by the t me the top of the stack has been reached, the app cat on term nates

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

How do exceptions work?


When an error cond t on occurs, the programmer can generate an except on by us ng the throw keyword, and the except on s tagged w th a p ece of data that dent fies exact y what has happened At
th s po nt, norma execut on stops and the except on-hand ng code bu t n to the app cat on beg ns
ook ng for a hand er It ooks n the current y execut ng rout ne, and f t finds a su tab e hand er, the
hand er s executed and the app cat on cont nues If t doesnt find a hand er n the current rout ne,
the except on-hand ng code moves one eve up the ca stack and checks for a su tab e hand er
there Th s process carr es on unt e ther the app cat on finds a hand er or t reaches the top eve n
the ca stackthe main funct on If noth ng has been found by th s t me, the app cat on term nates
w th an unhand ed except on message
Heres an examp e of how an unhand ed except on appears to you Youve probab y seen a ot of
these a ready! Look at the fo ow ng s mp e code fragment
Console::WriteLine("Exception Test");
int top = 3;
int bottom = 0;
int result = top / bottom;
Console::WriteLine("Result is {0}", result);

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

Chapter 11 Except on hand ng 177

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

What can you throw?


In trad t ona C++, you can attach any type of object to an except on, so you can use bu t- n
types (such as int and double) as we as structures and objects If you throw objects n C++, you
usua y throw and catch them by reference
NET anguages throw and catch objects that are of types nher t ng from the
System::Exception base c ass, so a though you can throw bu t- n types, you shou d use
Exception-der ved objects when youre wr t ng NET code

When should you throw?


You shou d use except ons to s gna cond t ons that are n some way except ona ; n other
words, s tuat ons that are unusua , and wh ch defin te y need attent on by the ca er Dont use
except ons for norma flow of contro n your app cat on For examp e, throw ng an except on
because your code cant find a fi e that ought to be present s fine; us ng an except on to s gna
that youve read to the end of a fi e snt, because that s a norma and expected occurrence,
not an except ona one

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

Using the try and catch construct


You catch except ons and process them by us ng the try/catch construct, wh ch has the fo ow ng
form
try
{
// code that may fail
}
catch(TypeOne ^one)
{
// handle this exception
}

180Microsoft Visual C++/CLI Step by Step

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

Chapter 11 Except on hand ng 181

Heres a br ef exerc se that demonstrates the use of Exception c ass propert es


1. Cont nue us ng the project from the prev ous exerc se Ed t the main funct on to set a back to

zero before the second ca to func


2. Ed t the catch statement n the main funct on to read as fo ows
catch(System::ArgumentException ^ex)
{
Console::WriteLine("Exception was {0}", ex->Message);
}

3. Bu d and run the app cat on

You shou d see a resu t ke th s


Exception was Aaargh!

In a s m ar way, you cou d use StackTrace to retr eve and pr nt the stack trace nformat on

Using the exception hierarchy


The except on c asses form a h erarchy based on System::Exception, and you can use th s h erarchy
to s mp fy your except on hand ng As an examp e, cons der System::ArithmeticException, wh ch
nher ts from System::Exception and has subc asses that nc ude System::DivideByZeroException and
System::OverflowException Now, ook at the fo ow ng code
try
{
// do some arithmetic operation
}
catch(System::ArithmeticException ^aex)
{
// handle this exception
}
catch(System::DivideByZeroException ^dex)
{
// handle this exception
}

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.

Chapter 11 Except on hand ng 183

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

Using exceptions with constructors


In the sect on What are except ons? ear er n th s chapter, I ment oned one of the advantages of except ons s that they make t poss b e for you to s gna an error where theres no way to return a va ue
Theyre very usefu for report ng errors n constructors, wh ch, as you now know, dont have areturn
va ue
In the fo ow ng exerc se, you see how to define a s mp e c ass that uses an except on to report
errors from ts constructor, and you a so see how to check for except ons when creat ng objects of
th s type
1. Create a new CLR Conso e App cat on project named CtorTest
2. Immed ate y after the using namespace System; ne and mmed ate y before main, add the

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.

184Microsoft Visual C++/CLI Step by Step

3. Try creat ng an object n the main funct on, as shown n the fo ow ng


int main()
{
Console::WriteLine("Exceptions in Constructors");
// Create a null handle to test the exception handling
String ^s = nullptr;
Test ^t = nullptr;
// Try creating an object
try
{
t = gcnew Test(s);
}
catch(System::ArgumentException ^ex)
{
Console::WriteLine("Exception: {0}",
ex->Message);
}
Console::WriteLine("Object construction finished");
return 0;
}

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

see the output from the catch b ock Try mod fy ng


the dec arat on of the str ng so that t po nts to a b ank str ng ( n t a ze t w th ), and then try
a nonb ank str ng (for examp e, he o) to check that the except on s thrown correct y

Nesting and rethrowing exceptions


Now that youve seen how to use the try/catch construct, ets move on to cover some more advanced
uses The first of these are nest ng and rethrow ng except ons
As the name mp es, nest ng except ons means nc ud ng one try/catch construct w th n another,
wh ch can prov de a usefu way to hand e error cond t ons It works as you m ght expect
try
{

// outer try block


try
{

// inner try block

// Do something
}
catch(SomeException ^ex1)
{
Console::WriteLine("Exception: {0}", ex1->Message);
}
}

Chapter 11 Except on hand ng 185

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

186Microsoft Visual C++/CLI Step by Step

3. Mod fy the main funct on so that t ooks ke th s


Console::WriteLine("Throw Test");
try
{
int n = 0;
Console::WriteLine("Calling with n=0");
func(n);
}
catch(ArgumentException ^ex)
{
Console::WriteLine("Exception caught in main()");
}
Console::WriteLine("All done");

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

Chapter 11 Except on hand ng 187

The finally block


C++/CLI adds a new construct to trad t ona C++ except on hand ng the finally b ock The purpose
of th s b ock s to et you c ean up after an except on has occurred, and the fo ow ng short exerc se
shows how t works
1. Cont nue us ng the project from the prev ous exerc se
2. Mod fy the ma n funct on so that t ooks ke the fo ow ng, add ng a finally b ock after the

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

188Microsoft Visual C++/CLI Step by Step

The catch() block


Standard C++ has a construct that can be used to catch any except on that goes past Heres how t
works
try
{
// do some arithmetic operation
}
catch(System::ArithmeticException ^pex)
{
// handle this exception
}
catch(...)
{
// handle any exception
}

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

Creating your own exception types


Youve a ready seen how a the except on types are der ved from the System::Exception c ass If you
cant find one that su ts your needs n the standard except on h erarchy, you can eas y der ve your
own c ass from Exception and use t n your code The fo ow ng exerc se shows you how to der ve a
new except on c ass and how to use t n code
1. Create a new CLR Conso e App cat on project named OwnException
2. Add the fo ow ng c ass defin t on mmed ate y after the using namespace System; ne
// User-defined exception class
ref class MyException : System::Exception
{
public:
int errNo;
MyException(String ^msg, int num) : Exception(msg), errNo(num) {}
};

Chapter 11 Except on hand ng 189

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;
}

190Microsoft Visual C++/CLI Step by Step

Ca ng the funct on w th a 0 va ue tr ggers the except on, wh ch s hand ed n the funct on


tse f, and the except on s then rethrown to be hand ed n the main funct on You can see n
the fo ow ng screen shot how the except on has been caught n both p aces

Using safe_cast for dynamic casting


C++ supports cast ng, wh ch s when you nstruct the comp er to convert one type to another for use
n an express on A though cast ng can be usefu , t can a so be dangerous because youre overr d ng
what the code wou d natura y d rect the comp er to do The safe cast keyword was ntroduced n
C++/CLI to he p make the operat on safer The fo ow ng code fragment shows how some convers on
operat ons can be unsafe
// Define the Vehicle and Car classes
ref class Vehicle {};
ref class Car : Vehicle {};
ref class Truck : Vehicle {};
ref class Bus : Vehicle {};
...
Car ^pc = gcnew Car(); // Create a Car
Vehicle ^pv = pc;
// Point to it using a Vehicle handle - OK
...
Car ^pc2 = pv;
// Copy pv into another Car^ handle - not OK!

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

Chapter 11 Except on hand ng 191

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.

Using exceptions across languages


One of the great th ngs about managed except ons n C++/CLI s that they work across anguages, so
now you can, for examp e, throw an except on n C++/CLI and catch t n a V sua Bas c app cat on No
onger are except ons s mp y a C++ feature, and th s ab ty to harmon ze error hand ng across code
wr tten n d fferent anguages makes m xed- anguage programm ng much eas er than t has been n
the past

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;

192Microsoft Visual C++/CLI Step by Step

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

Chapter 11 Except on hand ng 193

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.

7. Bu d the app cat on and execute t

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

Generate an except on.

Use the throw keyword, us ng a hand e to a managed


type as the argument. For examp e:
throw gcnew SomeException();

Catch an except on.

Use the try/catch construct, surround ng the code that


m ght fa w th a try b ock, fo owed by one or more catch
b ocks. Remember that you catch except ons by refer
ence, so you must use a hand e. For examp e:
try {
// code that might fail
}
catch(SomeException ^se)
{
// handle the exception
}

Catch more than one except on.

Cha n catch b ocks together. For examp e:


catch(SomeException ^ex)
{
// handle the exception
}
catch(SomeOtherException ^ex2)
{
// handle the exception
}

Catch a fam y of except ons.

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.

Catch every except on.

Use a catch b ock that takes Exception^ as a parameter,


wh ch w catch every type that s der ved from Exception.

Hand e except ons at more than one po nt n a program.

Use throw to rethrow except ons from one catch b ock to


another.

Create your own except ons.

Der ve from the Exception c ass, add ng your own


members.

Chapter 11 Except on hand ng 195

CHAPTER 12

Arrays and collections


After comp et ng th s chapter, you w

be ab e to

Imp ement arrays n C++

Create s ng e-d mens ona and mu t d mens ona arrays

Create and use managed arrays

Understand what gener c types are

Use the features of the System::Array c ass

Use the co ect on c asses prov ded by the NET Framework

Descr be what the STL/CLR brary s

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

Native C++ arrays


Nat ve arrays are those prov ded as part of the C++ anguage, and they are based on the arrays that
C++ nher ted from C A though nat ve arrays are des gned to be fast and effic ent, there are drawbacks assoc ated w th us ng them, as you see short y
Th s first exerc se ntroduces you to C++ nat ve arrays by show ng you how to create an array of
va ue types and how to use the array
1. Start M crosoft V sua Stud o 2012 and create a new CLR Conso e App cat on project named

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.

198Microsoft Visual C++/CLI Step by Step

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

4. Bu d and run the app cat on

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

Chapter 12 Arrays and co ect ons 199

Passing arrays to functions


Pass ng arrays to funct ons ntroduces a comp cat on because the funct on has no know edge about
the s ze of the array t has been passed As you see short y, when you pass an array to a funct on,
you pass on y the start ng address, wh ch means that you have to figure out some way of pass ng the
s ze nformat on a ong w th the array when you ca the funct on Norma y th s s accomp shed n one
of two ways

Pass the s ze as an exp c t parameter to the funct on ca


Ensure that the array s a ways term nated by a un que marker va ue so that the funct on can
determ ne when the end of the data has been reached

How do native arrays work?


A nat ve array n C++ snt an object; ts s mp y a co ect on of va ues strung together n memory So, a 10-e ement array of ntegers cons sts of 10 ntegers, one after the other, n memory
The name of the array represents the address of the first e ement, so when you dec are an array
ke th s
int foo[10];

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

200Microsoft Visual C++/CLI Step by Step

Lets nvest gate pass ng an array to a funct on


1. Cont nue w th the project from the prev ous exerc se
2. Add the fo ow ng funct on defin t on mmed ate y after the using namespace System; ne
void func(int arr[], size_t size)
{
Console::WriteLine("Size in func: {0}", sizeof(arr));
for(size_t i=0; i<size; i++)
Console::WriteLine(arr[i]);
}

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

Chapter 12 Arrays and co ect ons 201

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

202Microsoft Visual C++/CLI Step by Step

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

s ng e-d mens ona array, as fo ows


// Print the array content
for(int i=0; i<2; i++)
{
for(int j=0; j<3; j++)
Console::Write("{0} ", arr[i][j]);
Console::WriteLine();
}

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

Dynamic allocation and arrays


So far, a arrays n th s chapter have had a fixed s ze a ocated at comp e t me It s poss b eand very
commonto create arrays dynam ca y at run t me by us ng the new operator The array you create
st has a fixed s ze, but th s s ze can be spec fied at run t me when you know how many e ements you
need The fo ow ng exerc se shows how to create an array dynam ca y and then use t
1. Create a new CLR Conso e App cat on project named Dynamic
2. Open the source fi e Dynam c cpp and ed t the main funct on as shown
const size_t SIZE = 10;
int main(array<System::String ^> ^args)
{
Console::WriteLine("Dynamic Arrays");
// Create an array dynamically
int *pa = new int[SIZE];
// Fill the array
for(size_t i=0; i<SIZE; i++)
pa[i] = i*2;
// Print the array content
for(size_t j=0; j<SIZE; j++)
Console::WriteLine(pa[j]);
// Get rid of the array once we're finished with it
delete [] pa;
return 0;
}

Chapter 12 Arrays and co ect ons 203

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.

204Microsoft Visual C++/CLI Step by Step

Problems with manual memory management


Manua memory management s w de y cons dered to be the s ng e b ggest cause of bugs n C
and C++ programs, and ts the dr v ng force beh nd the deve opment of the garbage-co ect on
mechan sms n anguages such as C# and Java If ts up to the programmers to ca delete on
every p ece of memory they a ocate, m stakes are go ng to be made
There are two ma n prob ems assoc ated w th manua memory management

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

Chapter 12 Arrays and co ect ons 205

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

MyList<String^> ^listOfString = gcnew MyList<String^>();

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.

206Microsoft Visual C++/CLI Step by Step

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

array<int> ^intArray = gcnew array<int>(5);


for (int i=0; i<intArray->Length; i++)
intArray[i] = i*i;

Chapter 12 Arrays and co ect ons 207

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++)

6. Bu d and run the app cat on aga n

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 };

Arrays and reference types


Arrays of reference types are s ght y d fferent to arrays of va ue types Remember that reference
types are a ways accessed through a hand e Th s means that an array of reference types s actua y
go ng to be an array of hand es

208Microsoft Visual C++/CLI Step by Step

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

become very accustomed

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") };

Chapter 12 Arrays and co ect ons 209

Using the for each loop with arrays


In NET code, there s a better way to terate over arrays than us ng a counted for oop the for each
oop W th for each, you can terate over a co ect on w thout hav ng to ma nta n a counter Heres
what a for each oop ooks ke
for each (String ^s in arr)
{
// use s
}

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

210Microsoft Visual C++/CLI Step by Step

Th s short exerc se shows you how to use a for each oop


1. Cont nue w th the project from the prev ous exerc se
2. Mod fy the code that pr nts out the contents of the array to use a for each oop
for each (String ^s in arr) {
if (s == nullptr)
Console::WriteLine("null");
else
Console::WriteLine(s);
}

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 = {
},
},
}

Chapter 12 Arrays and co ect ons 211

The .NET array class


Managed arrays n the NET Framework a nher t from System::Array, wh ch means that every managed array has a number of usefu propert es and methods These propert es and methods are
summar zed n the fo ow ng two tab es
Property

Description

IsFixedSize

Returns true f the array has a fixed s ze. A ways returns


true, un ess overr dden by a der ved c ass.

IsReadOnly

Returns true f the array s read on y. A ways returns fa se,


un ess overr dden by a der ved c ass.

IsSynchronized

Returns true f the array s thread safe (synchron zed).


A ways returns fa se, un ess overr dden by a der ved c ass.

Length

Returns the tota number of e ements n a d mens ons of


the array as a 32 b t nteger.

LongLength

Returns the tota number of e ements n a d mens ons of


the array as a 64 b t nteger.

Rank

Returns the number of d mens ons n the array.

SyncRoot

Returns a po nter to an object that can be used to syn


chron ze access to the array.

Method

Description

AsReadOnly

Returns a read on y wrapper for an array.

BinarySearch

Stat c method that searches a s ng e d mens ona array for


a va ue by us ng a b nary search a gor thm.

Clear

Stat c method that sets a or part of an array to zero or a


nu reference.

Clone

Creates a sha ow copy of the array.

Copy

Stat c method that cop es a or part of one array to an


other array, perform ng type downcast ng as requ red.

CopyTo

Method that cop es a or part of one s ng e d mens ona


array to another.

Exists

Determ nes whether the array conta ns e ements that


match a cond t on.

Find

Return the first e ement of the array that matches a


cond t on.

FindAll

Return a the e ements of the array that match a


cond t on.

FindLast

Return the ast e ement of the array that matches a


cond t on.

ForEach

Performs an act on on each e ement of the array.

GetEnumerator

Returns an enumerator for the array. See the sect on


Us ng enumerators ater n th s chapter for deta s.

GetLength

Returns the number of e ements n a spec fied d mens on


as an nteger.

GetLowerBound

Returns the ower bound of a spec fied d mens on as an


nteger.

212Microsoft Visual C++/CLI Step by Step

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

6. Pr nt out the va ues n the array by us ng a s m ar pa r of nested oops


// Print out the array data
for (j=arr->GetLowerBound(0); j<=arr->GetUpperBound(0); j++)
for (k=arr->GetLowerBound(1); k<=arr->GetUpperBound(1); k++)
Console::WriteLine("pn[{0},{1}] = {2}", j, k, arr[j,k]);

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

214Microsoft Visual C++/CLI Step by Step

More advanced array operations


You can now create arrays, find out how many d mens ons they have and how arge they are, and get
and set va ues Th s sect on ntroduces some of the more advanced operat ons supported by the Array
c ass, such as copy ng, search ng, and sort ng

Copying array elements


The fo ow ng exerc se shows you how to use the Copy method to copy part of one array to another
1. Cont nue w th the project from the prev ous exerc se
2. At the end of the main funct on, create a second two-d mens ona array the same s ze and

type as the or g na
// Create another multidimensional array of ints
array<int, 2> ^arr2 = gcnew array<int, 2>(3,2);

3. Add some code to fi the new array w th a constant va ue


// Fill the array with a constant value
for (j=0; j<arr2->GetLength(0); j++)
for (k=0; k<arr2->GetLength(1); k++)
arr2[j,k] = 47;

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

5. Bu d and run the app cat on

Chapter 12 Arrays and co ect ons 215

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

create an array of str ngs


// Create an array of strings
array<String ^> ^sa = { "Dog", "Cat", "Elephant", "Gerbil", "Dog",
"Horse", "Pig", "Cat" };
// Check the length
Console::WriteLine("sa has length {0}", sa->Length);

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

216Microsoft Visual C++/CLI Step by Step

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

The sa array current y conta ns the fo ow ng entr es


Pig
Horse
Gerbil
Elephant
Dog
Dog
Cat
Cat

2. After the ca s to Sort and Reverse, add a new array


array<int> ^keys = { 6, 4, 3, 5, 2, 2, 1, 1 };

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

Chapter 12 Arrays and co ect ons 217

The IComparable interface


Any type that wants to be used n the Sort method must mp ement the IComparable nterface,
wh ch has one member, CompareTo When CompareTo s nvoked on an object, t s passed a
reference to another object The funct on returns 0 f the two nstances are equa , a negat ve
va ue f the object passed n s greater than the nstance ca ng the funct on, and a pos t ve
va ue f the object passed n has a esser va ue

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;

The IEnumerator nterface s defined n the System::Collection namespace, so ts eas er to use


enumerators f you add a using dec arat on for the namespace
2. Add the fo ow ng code to the end of the main funct on
Console::WriteLine("---Using Enumerator---");
IEnumerator ^ie = sa->GetEnumerator();
while (ie->MoveNext())
Console::WriteLine(ie->Current);

3. Bu d and run the app cat on

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 )

218Microsoft Visual C++/CLI Step by Step

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.

Other .NET collection classes


The System::Collections::Generic namespace conta ns severa very usefu co ect on c asses that you can
use n C++ programs Some of the most common y used are sted n the fo ow ng tab e A coup e of
them w be exam ned ater n more deta to g ve you an dea of how they work

Class

Description

Dictionary<K,V>

Stores a co ect on of key/va ue pa rs as a hashtab e

HashSet<T>

A co ect on of un que va ues

LinkedList<T>

A doub y nked st

List<T>

An expandab e array

Queue<T>

Stores a st of e ements and accesses them n the same


order n wh ch they were stored

SortedList<K,V>

A co ect on of key/va ue pa rs w th wh ch you can retr eve


e ements by ndex as we as by key

Stack<T>

Accesses a st of e ements from the top on y by us ng


Push and Pop operat ons

The List<T> class


The List<T> c ass, defined n the System::Collections::Generic namespace, s a dynam ca y expandab e
(and shr nkab e) array By defau t, nstances of th s c ass are res zab e and wr tab e, but the c ass prov des two stat c methods w th wh ch you can create read-on y and fixed-s ze Lists

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.

Chapter 12 Arrays and co ect ons 219

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 List c ass s defined n the System::Collections::Generic namespace By nsert ng a using


d rect ve, you can use the name w thout hav ng to fu y qua fy t every t me
3. Add the fo ow ng code to the main funct on
int main(array<String ^> ^args)
{
Console::WriteLine("List Demo");
// Create an empty List
List<int> ^lst = gcnew List<int>();
// Look at the count and capacity
Console::WriteLine("Capacity={0}", lst->Capacity);
Console::WriteLine("Count={0}", lst->Count);
// Adjust the capacity
lst->Capacity = 10;
Console::WriteLine("Capacity={0}", lst->Capacity);
// Add some elements
lst->Add(0);
lst->Add(2);
lst->Add(3);
lst->Insert(1, 1);
Console::WriteLine("Count is now {0}", lst->Count);
return 0;
}

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

220Microsoft Visual C++/CLI Step by Step

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

Other list operations


The List<T> c ass mp ements the same nterfaces as the System::Array c ass d scussed ear er n the
chapter, wh ch means that t prov des much of the same funct ona ty

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

The IEnumerable nterface prov des the GetEnumerator method

The ICloneable nterface prov des the Clone method

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

Chapter 12 Arrays and co ect ons 221

The SortedList<K,V> class


The SortedList<K,V> c ass, a so defined n the System::Collections::Generic namespace, represents a
co ect on of keys and va ues A SortedList s very s m ar to a Dictionary, wh ch a so ma nta ns key/
va ue pa rs, but the SortedList ma nta ns ts data n sorted-key order and a ows you to access tems
by ndex as we as by key
SortedList sorts ts entr es two ways

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;

The SortedList c ass s defined n the System::Collections::Generic namespace, and by nsert ng a


us ng d rect ve, you can use the name w thout hav ng to fu y qua fy t every t me
3. Add the fo ow ng code to the main funct on to create a SortedList and add some data to t
SortedList<String^, int> ^sl = gcnew SortedList<String^, int>();
sl->Add("Dilbert", 1044);
sl->Add("Wally", 2213);
sl->Add("Ted", 1110);
sl->Add("Alice", 3375);

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

222Microsoft Visual C++/CLI Step by Step

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

Other SortedList operations


You can use the IndexOfKey and IndexOfValue methods to return the ndex of a g ven key or va ue,
and both of them w return 1 f the key or va ue you spec fy doesnt ex st n the co ect on L kew se,
the ContainsKey and ContainsValue funct ons w return true f the co ect on conta ns a g ven va ue
orkey
If you want to de ete tems from the co ect on, you can use Remove to get r d of an tem by key
RemoveByIndex does the same th ng by ndex, and Clear can be used to remove a entr es

Chapter 12 Arrays and co ect ons 223

Generics and templates


If you are fam ar w th standard C++, you m ght be wonder ng how NET gener cs re ate to C++ temp ates, because they ook so s m ar (on the surface, at east) and seem n many cases to be do ng the
same job

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

There s no metaprogramm ng support for gener cs

Gener c types support constra nts on type parameters, wh ch temp ates do not

The STL/CLR library


One reason why temp ates are supported n C++/CLI s to perm t the use of the STL/CLR brary The
Standard Temp ate L brary (STL) s part of standard C++ It s best known for prov d ng a set of h ghperformance, extens b e co ect on c asses Th s sect on can on y g ve the br efest overv ew of what
the STL s and how t works
The STL conta ners are standard n unmanaged C++ code, and a vers on that works w th managed
types has been prov ded n the STL/CLR brary Th s has been done for two reasons F rst, many C++
deve opers are fam ar w th (and ke us ng) the STL conta ners, and th s enab es them to cont nue
to be product ve Second, the STL s a ot more extens b e and configurab e than the NET co ect on
c asses, and ts features m ght appea to deve opers ook ng for more performance and extens b ty

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.

224Microsoft Visual C++/CLI Step by Step

Here s a s mp e examp e to g ve you a fee for what STL/CLR code ooks ke


#include "stdafx.h"
#include <cliext\vector>
using namespace System;
using namespace cliext;
int main(array<System::String ^> ^args)
{
// Create a vector of int
vector<double> v1;
// Append values
for(int i=0; i<10; i++)
v1.push_back(i*2.0);
// Use an iterator to print all the values in order
vector<double>::iterator it = v1.begin();
for(; it != v1.end(); it++)
Console::WriteLine(*it);
return 0;
}

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

The three concepts behind STL


The STL s based on three concepts, wh ch have far-reach ng consequences for how conta ners are
wr tten and used
The first concept s that of the container In STL, the ma n job of a conta ner s to ho d ts e ements
A though th s m ght seem obv ous, many conta ner types n other brar es do a ot more bes des,
wh ch m ts the r adaptab ty For examp e, a though STL conta ners w a ocate memory for the r
members, you can prov de your own memory a ocator f you want And, f you want to sort the contents n some part cu ar way, you can do th s by prov d ng your own custom externa funct on rather
than hav ng to re y on the sort funct on that s bu t n to the conta ner

Chapter 12 Arrays and co ect ons 225

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

Create a fixed s ze array of C++ bu t n types.

Use a nat ve C++ array.

Create a managed array

Use the gener c array<> type. For examp e:


array<Person ^> ^people =
gcnew array<Person ^>();

terate over the members of a managed array.

Use a for each oop. For examp e:


List<Person> ^lst = new List<Person>();
...
for each (Person p in lst)
Console::WriteLine(p);

Create a dynam c array.

Use the List<> c ass.

Ma nta n a st of key/va ue pa rs.

Use the SortedList<> or Dictionary<> c asses.

Chapter 12 Arrays and co ect ons 227

CHAPTER 13

Properties
After comp et ng th s chapter, you w

be ab e to

Descr be what propert es are

Exp a n how propert es are supported by C++/CLI

Imp ement propert es

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

What are properties?


It s a ong-accepted pr nc p e of object-or ented programm ng that ts a bad dea to g ve users d rect
access to the data members that make up your c asses There are two ma n reasons for th s

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

The two kinds of properties


C++/CLI supports two k nds of propert es sca ar and ndexed
A scalar property g ves access to a s ng e va ue by us ng getter and setter code For examp e, a
Name property wou d mp ement getter and setter code to g ve access to the under y ng name data
Its mportant to note that a property doesnt have to represent a s mp e data member of the managed c ass; a property can represent der ved va ues For examp e, f a c ass has a date-of-b rth member, t wou d be poss b e to mp ement a property that ca cu ates the age Propert es can a so represent far more comp ex va ues, wh ch m ght nvo ve us ng data from other sources, such as search ng
databases or access ng URLs
An indexed property makes t poss b e for a property to be accessed as f t were an array, us ng the
trad t ona C++ square bracket notat on

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

230Microsoft Visual C++/CLI Step by Step

Implementing scalar properties


As ment oned n the prev ous sect on, a sca ar property s one that g ves you access to a s ng e data
member by us ng getter and setter code The fo ow ng exerc se shows you how to mp ement sca ar
propert es In th s examp e, we use a s mp e Person c ass conta n ng name and age members
1. Start M crosoft V sua Stud o 2012 and create a new CLR Conso e App cat on project named

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

Chapter 13 Propert es 231

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;
}

If anyone tr es to set the age to a negat ve va ue, an ArgumentException w


ca er that there s a prob em

232Microsoft Visual C++/CLI Step by Step

be thrown to a ert the

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

remov ng the data member


2. Bu d and run the app cat on, wh ch shou d work exact y the same as before

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

Read-only and write-only properties


You dont a ways have to prov de get and set methods for a property If you dont prov de a set
method, you end up w th a read-on y property If you om t the get method, you have a wr te-on y
property (wh ch s poss b e, but a ot ess common than the read-on y var ety)
The fo ow ng exerc se shows how to mp ement a read-on y property, and t a so ustrates how to
create a der ved property You change the Person c ass from the prev ous exerc se so that t nc udes
a date of b rth rather than an age The der ved Age property w then ca cu ate the persons age from
the date of b rth; ts obv ous y a der ved property because you cant change someones age w thout
chang ng h s or her date of b rth, as we Its a so obv ous y a read-on y property because ts a ways
ca cu ated and cannot be set by users of the c ass
1. E ther start a new CLR Conso e App cat on project or mod fy the one from the prev ous

exerc se

Chapter 13 Propert es 233

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

234Microsoft Visual C++/CLI Step by Step

resu t n a com-

Properties, inheritance, and interfaces


Propert es are first-c ass members of types, on the same eve as member funct ons and data members Th s means that you can use them n nher tance and n nterfaces Propert es can be v rtua and
even pure v rtua , and t snt necessary for both the get and set methods to have the same v rtua
spec fier
Th s exerc se shows you how to use a v rtua property when nher t ng from a base c ass
1. Create a new CLR Conso e App cat on project named PropertyInheritance
2. Immed ate y after the using namespace System; ne, define an abstract c ass ca ed Shape
public ref class Shape abstract
{
public:
virtual property double Area;
};

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

Chapter 13 Propert es 235

5. Create a Circle n main and pass t to the printArea funct on


Circle ^c = gcnew Circle(4.0);
printArea(c);

6. Bu d and run the app cat on

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

Implementing indexed properties


Now that you know how to mp ement a sca ar property, ets move on to cons der ndexed propert es, wh ch are a so known as indexers These are usefu for c asses that have data members that are
co ect ons of tems, and where you m ght want to access one of the tems n the co ect on

The Bank example


Cons der as an examp e a Bank c ass that ma nta ns a co ect on of Accounts If youre not us ng propert es, youd tend to see code such as the fo ow ng be ng used to access members of the Bank c ass
// Get a reference to one of the Accounts held by the Bank
Account ^acc = theBank->getAccount(1234567);

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;

Implementing the Bank class


The onger exerc se that fo ows wa ks you through mp ement ng the Bank and Account c asses, and t
a so shows you how to create and use both sca ar and ndexed propert es
1. Start V sua Stud o 2012 and create a new CLR Conso e App cat on project named Banker

236Microsoft Visual C++/CLI Step by Step

2. Add a new C++ header fi e named Bank.h to the project When the fi e opens n the ed tor,

ed t the c ass dec arat on so that ooks ke th s


#pragma once
ref class Bank
{
public:
Bank();
};

3. Add an mp ementat on fi e ca ed Bank.cpp to the project When t opens n the ed tor, ed t

the code so that t ooks ke th s


#include "stdafx.h"
using namespace System;
#include "Bank.h"
Bank::Bank()
{
Console::WriteLine("Bank: constructor");
}

4. To ensure that everyth ng s correct, open the Banker cpp fi e and add code to the main func-

t on to create a Bank object


int main(array<String ^> ^args)
{
Console::WriteLine("Bank Example");
// Create a Bank object
Bank ^theBank = gcnew Bank();
return 0;
}

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

Chapter 13 Propert es 237

Adding the Account class


The next stage nvo ves creat ng the Account c ass n very much the same way
1. Add a header fi e named Account.h to the project Ed t the header fi e so that t ooks

keth s
#pragma once
using namespace System;
ref class Account
{
public:
Account();
};

2. Add an mp ementat on fi e named Account.cpp that ooks ke th s


#include "stdafx.h"
using namespace System;
#include "Account.h"
Account::Account()
{
Console::WriteLine("Account: constructor");
}

3. Add some structure to the Account c ass Accounts w

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;

// the account number


// the current balance
// the overdraft limit

4. Open Account cpp Ed t the constructor defin t on and mp ementat on as fo ows so that three

va ues are passed n and used to n t a ze these three var ab es


Account::Account(long num, double bal, double lim)
{
Console::WriteLine("Account: constructor");
// Basic sanity check
if (num < 0 || lim < 0)
throw gcnew ArgumentException("Bad arguments to constructor");
// Initialize values
accNumber = num;
balance = bal;
limit = lim;
}

238Microsoft Visual C++/CLI Step by Step

Remember that you w


header fi e, as we

need to mod fy the dec arat on of the constructor n the Account h

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

Creating Account class properties


After the Account c ass has been constructed, you can add propert es to g ve access to the three data
members A three members are sca ar, so the propert es are easy to mp ement
1. Add a pub c property to Account h to a ow read-on y access to the account number, as

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

m ght be changed from t me to t me


property double OverdraftLimit
{
double get() { return limit; }
void set(double value) {
if (value < 0)
throw gcnew ArgumentException("Limit can't be negative");
limit = value;
}
}

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

Chapter 13 Propert es 239

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

5. Bu d and run the app cat on and check the output

Adding accounts to the Bank class


The purpose of the Bank c ass s to ho d Accounts, so the next step s to mod fy the Bank c ass to
ho da co ect on of Account objects Rather than des gn someth ng from scratch, you use the
System::Collections::Generic::List c ass (wh ch s ntroduced n Chapter 12, Arrays and co ect ons)
toho d the Accounts

Implementing the Add and Remove methods


The Add and Remove methods prov de a way to man pu ate the co ect on of Accounts he d by the
Bank c ass
1. Open the Bank h header fi e Add the fo ow ng two nes of code mmed ate y after the

#pragma once ne at the top of the fi e


using namespace System::Collections::Generic;
#include "Account.h"

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;
}

240Microsoft Visual C++/CLI Step by Step

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;
}

RemoveAccount checks whether an Account s n the st and, f present, removes t It snt


necessary to ca Contains because RemoveAccount w s ent y do noth ng f you try to remove
an tem that snt n the st However, users m ght be nterested n know ng that the account
theyre try ng to remove snt n the co ect on a ready
5. Add the fo ow ng ne of code to the Bank constructor to create the List member
accounts = gcnew List<Account^>();

6. Bu d the app cat on to ensure that there are no errors

Implementing an indexed property to retrieve accounts


You can now man pu ate the co ect on of Accounts, add ng and remov ng tems If you want to ook
up a part cu ar account, you probab y want to do so by the account number, and an ndexed property prov des a good way to access accounts by account number
Indexed propert es work n a very s m ar way to sca ar propert es, but you show the comp er that
you are defin ng an ndexed property by nc ud ng the ndex type n square brackets after the property name
property double Balance[long]

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) { ... }
}

Chapter 13 Propert es 241

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

242Microsoft Visual C++/CLI Step by Step

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

Chapter 13 Propert es 243

Quick reference
To

Do This

Create a property for a C++ c ass.

Use the property keyword and mp ement get and/or set


methods. For examp e:
property int Weight
{
int get() { ... }
void set(int w) { ... }
}

mp ement a s mp e property that requ res no og c n ts


get or set methods.

Use an auto mp emented property. For examp e:


property String ^Name;

mp ement a read on y property.

mp ement on y the get method.

mp ement a wr te on y property.

mp ement on y the set method.

mp ement an ndexed property.

mp ement a property that spec fies an ndex type n


square brackets, and whose get and set methods take an
ndex va ue that s used to determ ne wh ch va ue to get
or set. For examp e:
property Amount ^Pay[Person]
{
Amount ^get(Person^) { ... }
}

CHAPTER 14

Delegates and events


After comp et ng th s chapter, you w

Understand what de egates are

Create and use de egates

Exp a n what events are

Create and use events

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

What are delegates?


The funct on po nter mechan sm n C and C++ has been used by programmers for many years, and
ts a very usefu way of mp ement ng mechan sms such as event hand ers Unfortunate y, funct on
po nters are a C++ anguage feature, so theyre of no use n the NET env ronment, where features
need to be access b e from many anguages If youre nterested n know ng more about funct on
po nters and how they work, see the s debar that fo ows
De egates are the NET equ va ent of funct on po nters, and they can be created and used from
any NET anguage They can be used by themse ves, and they a so form the bas s for the NET event
mechan sm d scussed n the second part of th s chapter


245

What are function pointers?


W th a norma po nter, you can access a var ab e through the address t conta ns W th a funct on po nter, you can execute a funct on by us ng the address of the rout ne In exact y the same
way that you can use a po nter to ho d the addresses of d fferent var ab es, you can use the
same funct on po nter to nvoke d fferent funct ons And, n the same way that norma po nters
must have a type assoc ated w th them (so that you can on y access doub es w th a double*, for
examp e), funct on po nters must have a funct on s gnature assoc ated w th them
The fo ow ng ne of code shows how you dec are a funct on po nter n C++
long (*pf)(int, int);

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

You can nvoke the funct on nd rect y ke th s


pf = func1;
long l = pf(3,4);

// assign address of func1 to pf


// invoke func1() through pf

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

What is the purpose of delegates?


A de egate s a c ass whose purpose t s to nvoke one or more methods that have a part cu ar s gnature It s bas ca y an nd rect way of execut ng a funct on by de egat ng to an ntermed ate object
Heres a s mp e examp e to show when you m ght want to use a de egate
Imag ne that I want to be ab e to perform operat ons on numbers by pass ng a number nto a
funct on and gett ng a transformed va ue back, as demonstrated n the fo ow ng
double
double
result
result
result

d = 3.0;
result = Square(d);
= Cube(d);
= SquareRoot(d);
= TenToThePowerOf(d);

246Microsoft Visual C++/CLI Step by Step

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,

mmed ate y after the using namespace System; ne


delegate double NumericOp(double);

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

Chapter 14 De egates and events 247

Calling static member functions by using delegates


Lets start by ook ng at the s mp est case ca ng stat c member funct ons by us ng a de egate
1. Cont nue w th the project from the prev ous exerc se A the funct ons we want to ca need to

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

4. Bu d and run the app cat on

248Microsoft Visual C++/CLI Step by Step

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

the Cube funct on n the constructor


// Create a second delegate and use it to call cube
op = gcnew NumericOp(&Ops::Cube);
result = op(3.0);
Console::WriteLine("Result of Cube() is {0}", result);

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

Calling non-static member functions by using delegates


You can a so ca non-stat c member funct ons of c asses by us ng de egates By defin t on, a nonstat c member funct on must be ca ed on an object, so you need to spec fy to the de egate the
funct on ts go ng to ca and the object ts go ng to use You do so n the de egates constructor, as
ustrated here
// Declare a delegate bound to a non-static member
MyDelegate ^pDel = gcnew MyDelegate(myObject, &MyClass::MyFunction);

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

Using multicast delegates


Weve seen how ts poss b e to use a de egate to ca a s ng e funct on, but ts a so poss b e for a
de egate to ca more than one funct on w th a s ng e ca to Invoke A de egate that does so s ca ed
amulticast delegate and s der ved from the System::MulticastDelegate c ass

Chapter 14 De egates and events 249

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,

mmed ate y after the using namespace System; ne


delegate void NotifyDelegate(int);

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

250Microsoft Visual C++/CLI Step by Step

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;

6. You can now nvoke the mu t cast de egate as norma


// Invoke the multicast delegate
Console::WriteLine("Invoking del3");
del3(5);

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

Chapter 14 De egates and events 251

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

Delegates that return a result


You can, of course, use a de egate to ca a funct on that returns a resu t Here s an examp e
ref class JMath
{
public:
static double Square(double d) { return d*d; }
};
// Delegate to call a function that returns a double
delegate double MathOp(double d);
// Bind a delegate to Math::square
MathOp ^m = gcnew MathOp(&JMath::Square);
// Invoke the delegate
double result = m(3.3);

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

What are events?


Most, f not a , GUI p atforms support the dea of events, and events are very heav y used n GUI programm ng As an examp e, cons der a button Buttons dont ex st on the r own; they are used as part
of a user nterface and are conta ned by some other tem Th s tem s usua y a form, but t cou d a so
be some other contro , such as a too bar
The who e po nt of hav ng a button on a form s so that the user can c ck t to s gna h s ntent to
the app cat on and convey nstruct ons For examp e, the user c cked the OK button, so d sm ss the
d a og box or the user c cked the Pr nt button on the too bar, so pr nt the document
Events prov de a forma zed, standard mechan sm by wh ch event sources (such as a button) hook
up w th event rece vers (such as a form) Events n the NET Framework mp ement a pub sh-andsubscr be mechan sm, where event sources make pub c the events that they w ra sethey pub sh
themand event rece vers nform the source as to wh ch events theyre nterested nthey subscr be
to events Event rece vers can a so unsubscr be when they no onger want to rece ve a part cu ar
event
Events n the NET Framework are based on de egates, and as s ustrated n the d agram that
fo ows, t snt too hard to see how th s works An event source dec ares a de egate for each event
that t wants to generate, such as Click, DoubleClick, and so on An event rece ver then defines su tab e methods and passes them to the event source, wh ch adds them to ts de egates When the t me
comes to fire the event, the event source ca s Invoke on the de egate, thus ca ng the requ s te funct ons n the rece vers

Chapter 14 De egates and events 253

How do events differ from delegates?


Peop e are somet mes confused about the d fference between events and de egates because
they seem to be do ng very much the same task You have seen how a de egate prov des a way
to execute a funct on nd rect y, and th s cou d be used to mp ement event hand ng a button
cou d expose a de egate object for the c ck event, and you cou d b nd your hand er funct on to
t by us ng the += operator
There are two prob ems w th th s, however The first s that the buttons de egate wou d have
to be pub c n order to et c ents b nd to t, and th s means that anyone cou d nvoke the de egate Th s snt rea y des rab e; on y the button shou d be ab e to nvoke ts c ck de egate to
say t has been c cked The second prob em s that even though c ents cou d add and remove
event hand ers by us ng the += and = operators, t s a so poss b e to use the p a n = operator
Th s wou d reset the nvocat on st to conta n a s ng e tem, os ng any b nd ngs that m ght have
been set up by other c ents
Events so ve these two prob ems An event uses a de egate to prov de the under y ng
mechan sm, but t refines the behav or of a de egate n two ways

An event can on y be fired by the type that dec ares t


C ents can on y add and remove event hand er funct ons us ng += and = They cannot
use = to reset the nvocat on st

Implementing an event source class


The actua event mechan sm s mp fies the syntax so that you dont have to dea w th de egates
d rect y, and ts des gned to fit n w th the event mechan sm that a ready ex sts n M crosoft V sua
Bas c The fo ow ng exerc se takes you through creat ng an event source c ass and event rece ver
c asses that reg ster themse ves w th the source and use the events when theyre fired
1. Create a new CLR Conso e App cat on project named Event
2. Event sources and rece vers use de egates, so define a de egate for each of the events ra sed

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

254Microsoft Visual C++/CLI Step by Step

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

Chapter 14 De egates and events 255

How does the event keyword work?


When you dec are an event member for a managed c ass, the comp er generates code to
mp ement the under y ng de egate mechan sm For the OnFirstEvent event object n the exerc se, you get the fo ow ng methods generated

add OnFirstEvent, a pub c method that ca s Delegate::Combine to add a rece ver to


th sevents nvocat on st Rather than ca ng add OnFirstEvent d rect y, you use the
+= operator on the event object, wh ch ca s the method for you
remove OnFirstEvent, a pub c method that ca s Delegate::Remove to remove a rece ver
from th s events nvocat on st As w th the add funct on, you dont ca th s method
d rect y but nstead use the = operator on the event object
raise OnFirstEvent, a protected method that ca s Delegate::Invoke to ca a the methods
on th s events nvocat on st

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

Implementing an event receiver


You now have a c ass that can be used to fire events, so the next th ng you need s a c ass that w
sten for events and act upon them when theyve been generated
1. Cont nue w th the project from the prev ous exerc se and add a new c ass to the project

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

nu If the po nter s va d, save t away n the EvtSrc member


EvtRcv(EvtSrc ^src)
{
if (src == nullptr)
throw gcnew ArgumentNullException("Must have event source");
// Save the source
theSource = src;
}

256Microsoft Visual C++/CLI Step by Step

3. Define the member hand er funct ons n EvtRcv that EvtSrc s go ng to ca

As you know from


our d scuss on of de egates, the s gnatures of these methods must match the s gnatures of the
de egates used to define the events, as shown here

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

tor for the EvtRcv c ass so that t ooks ke the fo ow ng


EvtRcv(EvtSrc ^src)
{
if (src == nullptr)
throw gcnew ArgumentNullException("Must have event source");
// Save the source
theSource = src;
// Add our handlers
theSource->OnFirstEvent +=
gcnew FirstEventHandler(this, &EvtRcv::FirstEvent);
theSource->OnSecondEvent +=
gcnew SecondEventHandler(this, &EvtRcv::SecondEvent);
}

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

Chapter 14 De egates and events 257

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

unsubscr be from the first event

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

Hooking it all together


Now that youve wr tten the event source and event rece ver c asses, you can wr te some code to test
them out
1. Ed t the main funct on to create event source and rece ver objects
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);
return 0;
}

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!");

258Microsoft Visual C++/CLI Step by Step

src->RaiseTwo("One big step");


return 0;
}

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

Standard events and System::EventHandler


You can base an event on a de egate w th any s gnature, but the standard NET event mode requ res
that de egates conform to a part cu ar standard A standard event hand er funct ons have the fo owng form
void MyHandler(Object src, EventArgs ^args)

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

Chapter 14 De egates and events 259

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

260Microsoft Visual C++/CLI Step by Step

5. You now need some code that w

be ca ed when the event s fired, so add an Observer c ass

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

Chapter 14 De egates and events 261

Quick reference
To

Do This

Define a de egate.

Use the delegate keyword w th a funct on prototype. For


examp e:
delegate void DelegateOne(double d);

Create a de egate bound to a stat c c ass member.

Use gcnew to create a de egate object, pass ng nullptr for


the first parameter, and the address of the stat c funct on
as the second parameter. For examp e:
DelegateOne ^del = gcnew DelegateOne(
nullptr, &MyClass::MyFunc);

Create a de egate bound to a non stat c c ass member.

Use gcnew to create a de egate object, pass ng a hand e


to the nstance for the first parameter, and the address
of the member funct on as the second parameter. For
examp e:
DelegateOne ^del = gcnew DelegateOne(
myObject, &MyClass::MyOtherFunc);

Execute the funct on bound to a de egate.

Use the de egate s Invoke funct on, pass ng any param


eters requ red. For examp e:
del->Invoke(22.7);

Create an event.

F rst, define a de egate to define the hand er rout ne for


th s event, as fo ows:
delegate void ClickHandler(int, int);

Then, n the event source c ass, use the event keyword to


define an event object, ke th s:
event ClickHandler ^OnClick;

Ra se an event.

Use the event object as f t were a funct on, pass ng any


parameters. For examp e:
OnClick(xVal, yVal);

Subscr be to an event.

Use the += operator. For examp e:


src->OnClick += new ClickHandler(this,
&myHandler);

Unsubscr be from an event.

Use the = operator. For examp e:


src->OnClick -= new ClickHandler(this,
&myHandler);

Create an event that fo ows the standard EventHandler


pattern

262Microsoft Visual C++/CLI Step by Step

Use a System::EventHandler de egate. For examp e:


event EventHandler LimitReached;

CHAPTER 15

The .NET Framework class library


After comp et ng th s chapter, you w

be ab e to

Ident fy the components of the M crosoft NET Framework

Work w th the major components of the NET Framework

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

What is the .NET Framework?


The NET Framework s a comput ng p atform that has been des gned by M crosoft to s mp fy the
deve opment of modern app cat ons, such as the fo ow ng

App cat ons that use soph st cated GUI front ends

App cat ons that use the Internet

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

The Common Language Runtime


Youve a ready met the Common Language Runt me (CLR) because th s s the part of NET that manages your code as t runs, prov d ng serv ces such as garbage co ect on The CLR s a run-t me execut on
eng ne that s respons b e for execut ng code w th n the NET env ronment, prov d ng serv ces such as
secur ty, memory management, and remoting (commun cat on between objects n d fferent doma ns,
processes, or computers) Code that s run by the CLR s known as managed code; code that executes
outs de the contro of the CLR s unmanaged code A M crosoft V sua Bas c and C# code s managed,
but ts poss b e to wr te both managed and unmanaged code n M crosoft V sua C++ and to have
both types of code work ng together n the same app cat on

The Microsoft Intermediate Language


A NET anguages comp e down nto an ntermed ate form ca ed M crosoft Intermed ate Language
(MSIL, or just IL )
IL s s m ar to Java bytecode n that ts an ntermed ate form of code produced by the comp er
that cant be d rect y executed on a target system IL code s a so portab e and s a ways converted
nto nat ve code before ts executed, wh ch s done by a Just-In-T me (JIT) comp er Th s convers on
m ght happen on demand, funct on-by-funct on as an app cat on executes, or a at once when an
app cat on s nsta ed
One of the great nnovat ons of IL s that t snt s mp y a ow- eve , mach ne- ndependent object
code In fact, support for object-or ented funct ona tysuch as the deas of c asses, encapsu at on
and data-h d ng, po ymorph sm, and nher tance s bu t nto IL, so you can v ew t as a type of
object-or ented assemb er anguage Th s funct ona ty makes t far more powerfu than Java bytecode, and t makes t poss b e for you to perform cross- anguage object-or ented programm ng, eas y
ca ng members n C++/CLI c asses from V sua Bas c, and v ce-versa, and even nher t ng from a
C++/CLI c ass n V sua Bas c

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.

The Common Type System


The Common Type System (CTS) prov des a spec ficat on for how types are defined, managed, and
used, wh ch s an mportant part of the NET cross- anguage ntegrat on The CTS prov des a set of
ru es that anguages must obey, wh ch he ps to ensure that types created n d fferent anguages can
nteroperate w th one another

264Microsoft Visual C++/CLI Step by Step

The Common Language Specification


The Common Language Spec ficat on (CLS) s a set of ru es and constra nts that comp er and brary
wr ters need to fo ow to ensure that the anguages and code they produce w nteroperate w th
other NET anguages The CLS forms a subset of the CTS, and f a anguage or a brary s CLS-comp ant,
t w comp ete y nteroperate w th other CLS-comp ant anguages
You see n the on ne documentat on that some NET member funct ons are marked as not CLScomp ant, wh ch means that they m ght not be access b e from some NET anguages For examp e,
funct ons that use uns gned ntegers are not CLS-comp ant because uns gned ntegers arent supported
by V sua Bas c As a resu t, uns gned ntegers are not nc uded n the types spec fied by the CLS

The .NET Framework class library


The NET Framework c ass brary s an object-or ented brary of c asses that prov des a the too s you
need to wr te a w de var ety of app cat ons
S nce W ndows was first re eased, programmers have wr tten W ndows app cat ons us ng the
W ndows API (app cat on programm ng nterface) Th s API g ves you a arge number of C funct ons
severa thousand, n factthat you can ca from your app cat ons to nteract w th W ndows However,
there are two ma n prob ems w th the W ndows API first, t snt object-or ented, and second, ts a
C brary, so t cant eas y be used from every anguage
One of the benefits of object-or ented programm ng s the he p that t g ves n structur ng and
manag ng arge-sca e projects The W ndows API has grown to severa thousand funct ons, and t
becomes harder and harder to manage such a arge co ect on of unstructured rout nes In add t on
to ts other benefits (such as encapsu at on and po ymorph sm), object-or ented programm ng ets
you mpose a structure on code So, for examp e, a Dialog c ass can conta n a the funct ons re at ng
to d a og boxes Th s ab ty makes t much eas er to use a brary the s ze of the W ndows API
The second prob em w th the W ndows API s that ts bas ca y wr tten for C programmers, so t
uses many features that are un que to C, such as po nters and nu -term nated str ngs, wh ch makes
t hardand somet mes mposs b eto use some funct ona ty from anguages other than C or C++
You a so tend to need a ot of ug y p umb ng to nterface between anguages such as V sua Bas c
and the API
The NET Framework c ass brary prov des a set of c asses that can be used from any NET anguage because t works at the IL eve A NET anguages comp e down to the same ntermed ate
code, and because they a use references and agree on the bas c set of va ue types, they can a use
the c asses defined n the c ass brary Th s s a huge advantage and prov des anguage nteroperab ty
on a sca e never seen before

Chapter 15 The .NET Framework c ass brary 265

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

The types that are exported by the assemb y

Other assemb es on wh ch th s one depends

Secur ty perm ss ons needed to run

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

266Microsoft Visual C++/CLI Step by Step

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

The fi e conta ns a number of nes that ook ke the fo ow ng


[assembly:AssemblyTitleAttribute("Meta1")];
[assembly:AssemblyDescriptionAttribute("")];
[assembly:AssemblyConfigurationAttribute("")];
[assembly:AssemblyCompanyAttribute("")];
[assembly:AssemblyProductAttribute("Meta1")];
[assembly:AssemblyCopyrightAttribute("Copyright (c)
[assembly:AssemblyTrademarkAttribute("")];
[assembly:AssemblyCultureAttribute("")];

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

Chapter 15 The .NET Framework c ass brary 267

7. Doub e-c ck MANIFEST, wh ch opens a separate w ndow d sp ay ng the assemb y metadata

At the top of th s st ng are the deta s of the assemb es on wh ch th s executab e depends


Scro down unt you find the AssemblyCompanyAttribute ne, wh ch shou d read someth ng
ke the fo ow ng
.custom /*0C000005:0A000009*/ instance void
['mscorlib'/* 23000001 */]
'System.Reflection'.'AssemblyCompanyAttribute'
/* 0100000D */::.ctor(string) /* 0A000009 */
= ( 01 00 16 41 63 6D 65 20 52 6F 63 6B 65 74 20 53
// ...City Power &
6C 65 64 2C 20 49 6E 63 2E 00 00 )
// Light...

A though the contents are presented n hexadec ma , you can see that the metadata does
reflect the change you made to the project

The .NET Framework namespaces


The NET Framework c ass brary s made up of a set of c asses, nterfaces, structures, and enumerat ons that are conta ned n over 400 namespaces Th s sect on beg ns by exp a n ng how to use
namespaces n C++/CLI code and then goes on to st some of the major NET namespaces, together
w th br ef deta s of the r funct on and content
268Microsoft Visual C++/CLI Step by Step

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

// the List<T> class from


// System::Collections::Generic
// the Thread class from System::Threading

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

Chapter 15 The .NET Framework c ass brary 269

Using namespaces in C++ applications


C++/CLI app cat ons emp oy the #using preprocessor d rect ve to mport metadata nto app cat ons
Remember that metadata s nformat on that descr bes the types n an assemb y, and t nc udes the
fu y qua fied names of a the types For examp e, f the comp er sees a ne such as
#using <mscorlib.dll>

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

The System namespace


The System namespace, defined n mscor b d , conta ns a ot of fundamenta c asses, nc ud ng the
fo ow ng

Base c asses for common y used va ue and reference types, p us the base c ass for arrays

Events and event hand ers

De egates and nterfaces

Attr butes

Except ons

Math

270Microsoft Visual C++/CLI Step by Step

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

Floating-point and decimal arithmetic


Chapter 8, Inher tance, po nts out that float ng-po nt ca cu at ons are subject to round ng
errors Th s s because of the way that IEEE-754 encodes va ues by us ng base 2, wh ch means t
s not poss b e to represent some dec ma numbers exact y In the same way that p cannot be
exact y represented as a dec ma (3 14159), a dec ma va ue such as 0 1 cannot be exact y represented n base 2 ar thmet c t comes out as 00011001100110011 w th the 0011 repeatng forever Th s means that you can on y ever get an approx mat on to 0 1, n the same way
that we can on y ever get an approx mat on to the correct va ue of p , and so we see round ng
errors as these approx mat ons accumu ate
There are two ways around th s prob em The first s to use the System::Decimal type, wh ch
performs ar thmet c n base 10 and so does not get these round ng errors, but wh ch s s ower
The second s to use nteger ar thmet c w th sca ng For examp e, nstead of us ng 123 45, use
12345 and d v de the resu t by 100

The Collections namespaces


Chapter 12, Arrays and co ect ons, ooks at the Collections namespaces, n part cu ar System::
Collections::Generic System::Collections::Generic s mp emented n mscor b d , so to use t, you
haveto nc ude a #using statement, as demonstrated here
#using <mscorlib.dll>

272Microsoft Visual C++/CLI Step by Step

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

The Windows namespaces


The System::Windows prefix dent fies 50 namespaces that together prov de the funct ona ty of
W ndows Presentat on Foundat on (WPF), an advanced user nterface (UI) framework for NET ntroduced n vers on 3 0 WPF prov des a the too s you need to create modern UIs, nc ud ng support
for forms-based app cat ons, 2D and 3D graph cs, typography and pr nt ng, run-t me an mat on, and
comprehens ve support for p ay ng med a

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

The Net namespaces


Network ng support s prov ded by a number of namespaces n the System::Net fam y System::Net tse f
prov des an nterface to many of the protoco s common y used today, such as man pu at ng IP addresses,
mak ng DNS ookups, ta k ng to HTTP and FTP servers, manag ng cook es, and authent cat on
System::Net::Sockets prov des an mp ementat on of the Berke ey Sockets protoco and prov des a
NET wrapper around the W ndows W nSock API, whereas System::Net::WebSockets prov des a managed mp ementat on of the WebSocket nterface

The ServiceModel namespaces


The System::ServiceModel namespaces (over 30 of them) together mp ement W ndows Commun cat on Foundat on (WCF), a techno ogy ntroduced n NET 3 0 for creat ng d str buted, serv ce-or ented
app cat ons
W th WCF, you can bu d app cat ons out of components hosted n other processes, and even on
other computers Th s has ong been poss b e, but the techno og es used were very d fferent, dependng on where your components were ocated (same process, d fferent process on the same computer,
or d fferent process on another computer) and the commun cat on mechan sm you wanted to use
(TCP/IP, HTTP, messag ng)
WCF prov des an ntegrated framework for creat ng, dep oy ng, and manag ng d str buted components and the r c ents Chapter 19 shows you how to wr te a web serv ce by us ng WCF

Chapter 15 The .NET Framework c ass brary 275

The Xml namespaces


XML s heav y used throughout the NET Framework, and severa namespaces prov de support for
creat ng and man pu at ng XML, nc ud ng the fo ow ng

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::Schema Prov des support for XML schemas

System::Xml::Serialization G ves you the ab ty to ser a ze NET objects to and from XML

System::Xml::XPath Conta ns the XPath parser and eva uat on eng ne

System::Xml::Xsl Conta ns the Extens b e Sty esheet Language (XSL) processor

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 Data namespaces


The System::Data namespaces ho d the c asses that mp ement ADO NET, a framework w th wh ch
you can bu d components to manage data from a number of data sources Data from d fferent data
sources s prov ded by data prov ders, five of wh ch are sh pped w th the NET Framework

System.Data.OleDb Object L nk ng and Embedd ng Database (OLE DB)based techno ogy


that makes t poss b e to use many d fferent k nds of data sourcessuch as re at ona database tab es, M crosoft Exce spreadsheets, and even text fi esas f they were databases
System.Data.Odbc The ODBC prov der g ves access to Open Database Connect v ty (ODBC)
data sources, nc ud ng M crosoft Access databases
System.Data.SqlClient Th s prov der s opt m zed for use w th M crosoft SQL Server
System.Data.OracleClient The prov der for Orac e makes t poss b e to work w th Orac e
databases from NET code
System.Data.EntityClient Ent ty Framework (EF) s an object-re at ona mapp ng framework
that can be used from ADO NET, mak ng t poss b e to map managed objects to a back ng
database automat ca y

276Microsoft Visual C++/CLI Step by Step

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

The Web namespaces


Because one of the ma n reasons for ntroduc ng the NET Framework was to make t eas er to bu d
web app cat ons, ts perhaps no surpr se that the NET Framework conta ns a number of namespaces
re ated to web programm ng These are a re ated to M crosoft ASP NET, the atest vers on of M crosoft Act ve Server Pages techno ogy that s opt m zed to work n the NET env ronment
The most s gn ficant of the Web namespaces are sted here

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::Security Th s prov des c asses that mp ement secur ty n ASP NET

System::Web::Services Th s prov des the c asses w th wh ch you can bu d web serv ces

System::Web::UI Th s conta ns a the c asses w th wh ch you can bu d server-s de contro s

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

Chapter 15 The .NET Framework c ass brary 277

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

Use data structures such as dynam c arrays, sts, and hash


tab es.

Use the c asses n the System::Collections::Generic


namespace.

Create a form based app cat on.

Use the c asses n System::Windows::Forms, and der ve a


c ass from System::Windows::Forms::Form.

Work w th XML.

Look at the c asses n the System::Xml namespace.

Trace app cat on execut on, nteract w th the event og,


or mon tor system performance.

Use the c asses n the System::Diagnostics namespace.

Work w th databases by us ng ADO.NET.

Look at the System::Data namespaces.

278Microsoft Visual C++/CLI Step by Step

PAR T I I I

Using the .NET


Framework
CHAPTER 16

Work ng w th fi es . . . . . . . . . . . . . . . . . . . . . . . . . . .

281

CHAPTER 17

Read ng and wr t ng XML

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

Introduc ng W ndows Store apps

369

CHAPTER 21

More about W ndows Store apps

397


279

CHAPTER 16

Working with files


After comp et ng th s chapter, you w

be ab e to

Understand how the M crosoft W ndows NET Framework performs nput/output (I/O)

Ident fy the c asses that make up the System::IO namespace

Perform text I/O

Read and wr te fi es

Work w th fi es and d rector es

Perform b nary I/O

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

The System::IO namespace


The System::IO namespace conta ns a the c asses that are used for b nary and text I/O as we as
c asses that he p you to work w th fi es and d rector es The fo ow ng tab e sts the ma n c asses n the
namespace
Class

Description

BinaryReader

Reads pr m t ve data types as b nary va ues

BinaryWriter

Wr tes pr m t ve data types as b nary va ues

BufferedStream

A stream c ass that buffers reads and wr tes to another


stream

Directory

Has stat c methods for work ng w th d rector es

DirectoryInfo

Has non stat c methods for work ng w th d rector es

File

Has stat c methods for work ng w th fi es

FileInfo

Has non stat c methods for work ng w th fi es

FileStream

A c ass for read ng and wr t ng fi es by us ng a stream

FileSystemInfo

The abstract base c ass for DirectoryInfo and FileInfo

FileSystemWatcher

Watches for changes to the fi e system and ra ses events


when changes occur

IOException

The except on thrown by c asses n the System::IO


namespace

MemoryStream

A stream c ass that reads and wr tes memory

Path

He ps you work w th d rectory str ngs n a p atform


ndependent way

Stream

The abstract base c ass for a the stream c asses

StreamReader

A TextReader that reads characters from a byte stream

StreamWriter

A TextWriter that wr tes characters to a byte stream

StringReader

A TextReader that reads from a str ng

StringWriter

A TextWriter that wr tes to a str ng

TextReader

The abstract base c ass for StreamReader and


StringReader

TextWriter

The abstract base c ass for StreamWriter and StringWriter

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

Th s chapter focuses on the atter two groups

282Microsoft Visual C++/CLI Step by Step

Implementing text I/O by using readers and writers


TextReader and TextWriter are the abstract base c asses for a group of c asses that are used to
read and wr te characters There are four c asses n System::IO that der ve from these two bases
StreamReader, StreamWriter, StringReader, and StringWriter, as we as w th severa other much more
spec a zed wr ter c asses n other namespaces

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

C oses the wr ter and re eases any resources that t s us ng

Dispose

Re eases a unmanaged resources used by the wr ter and


opt ona y re eases managed resources, as we

Flush

Causes a buffered data to be wr tten to the under y ng


dev ce

FlushAsync

Causes a buffered data to be wr tten asynchronous y to


the under y ng dev ce

Synchronized

Creates a thread safe wrapper for the wr ter

Write

Wr tes text w thout a new ne

WriteAsync

Wr tes text w thout a new ne asynchronous y

WriteLine

Wr tes text w th a new ne

WriteLineAsync

Wr tes text w th a new ne asynchronous y

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

Chapter 16 Work ng w th fi es 283

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

A FileStream object that takes bytes as nput and wr tes them to a fi e

A StreamWriter object that takes text and converts t to a byte stream

So, ets get started


1. Start M crosoft V sua Stud o 2012 and create a new CLR Conso e App cat on project named

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

beg nn ng of the app cat on, as shown here


using namespace System::IO;

3. In the main funct on, create a FileStream object to wr te to a fi e


// Create a FileStream
try
{
FileStream ^fs = gcnew FileStream("output.txt", System::IO::FileMode::Create);
}
catch(System::Exception ^pe)
{
Console::WriteLine(pe->ToString());
}

The FileStream constructor takes a fi e name and a mode In th s case, the fi e s go ng to be


created f t doesnt ex st or overwr tten f t does Ive used output txt as the fi e name, but you
can spec fy any path and fi e name you ke for the new fi e

Note See the section The FileStream class later in this chapter for more details on
how to construct FileStream objects.

284Microsoft Visual C++/CLI Step by Step

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

The StreamWriter constructor takes a hand e to a Stream object as ts one argument


5. You can now use the Write and WriteLine funct ons to output text to the fi e P ace the fo ow-

ng nes ns de the try b ock


// Write some text
sw->WriteLine("First line");
sw->WriteLine("Second line");
sw->WriteLine("Third line");

6. Ensure that a output s flushed to the fi e and c ose the stream


// Close the file
sw->Flush();
sw->Close();

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.

7. Bu d and run the app cat on

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

Chapter 16 Work ng w th fi es 285

1. Create a new CLR Conso e App cat on project named CppReader


2. Inc ude a using dec arat on for System::IO at the top of the project
using namespace System::IO;

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

In th s case, youre open ng the fi e by us ng FileMode::Open, wh ch w


the fi e doesnt a ready ex st

288Microsoft Visual C++/CLI Step by Step

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

Chapter 16 Work ng w th fi es 289

Working with files and directories


The System::IO namespace conta ns severa c asses to he p you work w th fi es and d rector es

Getting information about files and directories


The Directory and DirectoryInfo c asses prov de you w th funct ons to he p you work w th d rector es
The d fference between them s that the Directory c ass on y conta ns stat c methods, whereas
DirectoryInfo conta ns non-stat c nstance methods Why the need for two d fferent c asses? Its
necessary for NET to perform a secur ty check before a ow ng you access to a d rectory or a fi e The
Directory c ass performs th s check every t me you use one of ts stat c methods, wh ch can be t meconsum ng Objects of the DirectoryInfo c ass, on the other hand, work w th one d rectory, and the
secur ty check s done once when the object s constructed It can, therefore, be a ot more effic ent to
use DirectoryInfo f youre go ng to perform mu t p e operat ons on one d rectory The fo ow ng tab e
sts the ma n methods of the Directory c ass
Method

Description

CreateDirectory

Creates a d rectory

Delete

De etes a d rectory and, opt ona y, ts subd rector es

EnumerateDirectories

Returns an enumerab e co ect on of the d rector es n a


spec fied path

EnumerateFiles

Returns an enumerab e co ect on of the fi es n a spec


fied path

EnumerateFileSystemEntries

Returns an enumerab e co ect on of a the fi es and


d rector es n a spec fied path

Exists

Checks whether a d rectory ex sts

GetCreationTime

Gets the creat on t me of a d rectory

GetCurrentDirectory

Returns a str ng represent ng the path to the app cat on s


current d rectory

GetDirectories

Gets an array of str ngs represent ng the names of subd


rector es n a g ven d rectory

GetDirectoryRoot

Returns the root port on of a path

GetFiles

Gets an array of str ngs represent ng the names of the


fi es n a g ven d rectory

GetFileSystemEntries

Gets an array of str ngs represent ng the names of the


fi es and d rector es n a g ven d rectory

GetLastAccessTime

Gets the ast access t me for the d rectory

GetLastWriteTime

Gets the ast wr te t me for the d rectory

GetLogicalDrives

Gets a st of the og ca dr ves on the computer

GetParent

Gets the parent d rectory of a spec fied d rectory

Move

Moves a d rectory and ts contents

SetCreationTime

Sets the creat on t me for a d rectory

290Microsoft Visual C++/CLI Step by Step

1. Create a new CLR Conso e App cat on named CppFiles


2. Because a the fi e and d rectory c asses are part of System::IO, add a using dec arat on at the

beg nn ng of the app cat on


using namespace System::IO;

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

294Microsoft Visual C++/CLI Step by Step

void ParseOptions(String ^opts, bool &size, bool &date, bool &atts)


{
opts = opts->ToLower();
if (opts->Contains("v"))
{
size = date = atts = true;
}
else
{
if (opts->Contains("s")) size = true;
if (opts->Contains("d")) date = true;
if (opts->Contains("a")) atts = true;
}
}

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

Chapter 16 Work ng w th fi es 295

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

st subd rector es first, fo owed


by fi es; d rectory names w be pr nted n uppercase etters, and fi e names n owercase, but
you can obv ous y change th s to d sp ay them however you want Add the fo ow ng code for
st ng the subd rector es

296Microsoft Visual C++/CLI Step by Step

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

the Now do the fi es comment


array<String^> ^files = Directory::GetFiles(di->ToString());
for (int i=0; i<files->Length; i++)
{
FileInfo ^fi = gcnew FileInfo(files[i]);
ProcessFile(fi, size, date, atts);
}

As you can see, t s s mp y a case of retr ev ng a st of fi e names by us ng GetFiles, creat ng a


FileInfo object for each fi e, and then pass ng t to the processFile funct on
11. Bu d the app cat on, open a conso e w ndow, and then change to the projects Debug d rec-

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

Chapter 16 Work ng w th fi es 297

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

The BinaryWriter class


The fo ow ng tab e sts the methods prov ded by BinaryWriter
Method

Description

Close

C oses the wr ter and the under y ng stream

Dispose

Re eases a unmanaged resources used by the wr ter and,


opt ona y, re eases managed resources, as we

Flush

Causes a buffered data to be wr tten to the under y ng


dev ce

Seek

Sets the seek pos t on w th n the under y ng stream

Write

Wr tes a va ue to the stream

Write7BitEncodedInt

Wr tes a 32 b t nteger n a compressed format

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.

298Microsoft Visual C++/CLI Step by Step

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

300Microsoft Visual C++/CLI Step by Step

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

The FileStream wr tes to a fi e, creat ng t f necessary, and the fi e w be opened w th read/


wr te access because you be read ng from t ater n the app cat on Aga n, ts good pract ce
to put the I/O c ass creat on code n a try b ock to catch any prob ems that m ght occur The
finally b ock ensures that the fi e s c osed, no matter what happens, but you obv ous y do not
want to do th s f creat ng the FileStream fa ed

Chapter 16 Work ng w th fi es 301

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

Streams and seek pointers


Every stream n NET has a seek pointer assoc ated w th t, wh ch represents the pos t on n the
stream at wh ch the next read or wr te operat on w take p ace Th s po nter s automat ca y
repos t oned when you use Stream c ass methods to read or wr te the stream, but ts a so poss b e to move th s po nter yourse f f you need to (and f you know what youre do ng)
The most ke y t me you need to move the po nter s when you open a stream for read/
wr te access After youve wr tten to the stream, the seek po nter s pos t oned at the end, ready
for the next wr te If you want to read from the stream, you have to repos t on the po nter
You repos t on the po nter by us ng the Seek method of the Stream object, g v ng t an offset
n bytes and a pos t on where the offset shou d be app ed Offsets can be pos t ve or negat ve,
the s gn reflect ng whether the offset shou d move toward the start (negat ve) or end (pos t ve)
of the stream The poss b e pos t ons are members of the SeekOrigin enumerat on, and they
can be SeekOrigin::Current (the current pos t on), SeekOrigin::Begin (the start of the Stream), or
SeekOrigin::End (the end of the Stream)

302Microsoft Visual C++/CLI Step by Step

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.

Create a StreamWriter that outputs to a FileStream


and then use the Write and WriteLine members of
StreamWriter. For examp e:
FileStream ^fs = gcnew FileStream("foo.txt",
FileMode::Append);
StreamWriter ^sw = gcnew StreamWriter(fs);
sw->WriteLine("Some text");

F ush and c ose the StreamWriter when you re fin shed


w th t. For examp e:
sw->Flush();
sw->Close();

Read text from a fi e.

Create a StreamReader that reads from a FileStream and


then use the ReadLine member of StreamReader. For ex
amp e:
FileStream ^fs = gcnew FileStream("foo.txt",
FileMode::Open);
StreamReader ^sr = gcnew StreamReader(fs);
String ^line = sr->ReadLine();

Chapter 16 Work ng w th fi es 303

C HAP TE R 17

Reading and writing XML


After comp et ng th s chapter, you w

be ab e to

Understand why XML s so mportant to M crosoft NET

Descr be the c asses that make up the NET XML namespaces

Parse XML fi es by us ng XmlTextReader.

Va date XML by us ng XmlValidatingReader.

Wr te XML by us ng XmlTextWriter.

Use the XmlDocument c ass to man pu ate XML n memory

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.

XML and .NET


One of the major features of the NET Framework s that t makes t poss b e for you to eas y produce
d str buted app cat ons that are anguage- ndependent and that w be p atform- ndependent when
NET s ported to other p atforms XML p ays a major part n th s p an by act ng as a s mp e, portab e
g ue ayer thats used to pass data around n d str buted app cat ons


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

Parsing XML by using XmlReader


Lets start by ook ng at how you can parse XML by us ng the XmlReader c ass An XmlReader prov des
you w th a way to parse XML data that m n m zes resource usage by read ng forward through the
document, recogn z ng e ements as t reads Very tt e data s cached n memory, but the forwardon y sty e has two ma n consequences The first s that t snt poss b e to go back to an ear er po nt
n the fi e w thout read ng from the beg nn ng aga n The second consequence s s ght y more subt e
E ements are read and presented to you one by one, w th no context So, f you need to keep track of
where an e ement occurs w th n the document structure, you need to do t yourse f If e ther of these
consequences sounds ke m tat ons to you, you m ght need to use the XmlDocument c ass, wh ch s
d scussed n the sect on Us ng XmlDocument ater n th s chapter
XmlReader uses a pull model, wh ch means that you ca a funct on to get the next node when
youre ready Th s mode s n contrast to the w de y used S mp e API for XML (SAX) API, wh ch uses a
push model, mean ng that t fires events at ca back funct ons that you prov de The fo ow ng tab es
st the ma n propert es and methods of the XmlReader c ass

Property

Description

AttributeCount

Returns the number of attr butes on the current node

Depth

Returns the depth of the current node n the tree

Encoding

Returns the character encod ng of the document

EOF

Returns true f the reader s at the end of the stream

HasAttributes

Returns true f the current node has any attr butes

HasValue

Returns true f the current node can have a va ue

IsEmptyElement

Returns true f the current e ement has no va ue

Item

Gets the va ue of an attr bute

LocalName

Returns the name of the current e ement w thout a


namespace prefix

Name

Returns the fu name of the current e ement

NamespaceURI

Gets the namespace UR for the current node

Chapter 17 Read ng and wr t ng XML 307

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

The fo ow ng exerc se shows you how to read an XML document by us ng an XmlReader Fo ow ng


s the samp e XML document used by th s exerc se and the other exerc ses n th s chapter Th s document sts deta s of three vo canoes and conta ns many common XML constructs
<?xml version="1.0" ?>
<!-- Volcano data -->
<geology>
<volcano name="Erebus">
<location>Ross Island, Antarctica</location>
<height value="3794" unit="m"/>
<type>stratovolcano</type>
<eruption>constant activity</eruption>
<magma>basanite to trachyte</magma>
</volcano>
<volcano name="Hekla">
<location>Iceland</location>
<type>stratovolcano</type>
<height value="1491" unit="m"/>
<eruption>1970</eruption>
<eruption>1980</eruption>
<eruption>1991</eruption>
<magma>calcalkaline</magma>
<comment>The type is actually intermediate between crater row
and stratovolcano types</comment>
</volcano>
<volcano name="Mauna Loa">
<location>Hawaii</location>
<type>shield</type>
<height value="13677" unit="ft"/>
<eruption>1984</eruption>
<magma>basaltic</magma>
</volcano>
</geology>

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

Chapter 17 Read ng and wr t ng XML 311

3. Add th s code to the beg nn ng 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: CppXmlReader [path]");
return -1;
}
String ^path = gcnew String(args[0]);

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
}

312Microsoft Visual C++/CLI Step by Step

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

Chapter 17 Read ng and wr t ng XML 313

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

The first few nes of the output shou d ook ke th s


->
->
->
->
->
->
->
->
->
->
->
->
->

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

Verifying well-formed XML


XML that s correct y constructed s ca ed well-formed XML, wh ch means that e ements are correct y
nested and that every e ement tag has a match ng end-e ement tag If the XmlReader encounters
bad y formed XML, t w throw an XmlException to a ert you as to what t th nks s wrong As w th a
pars ng errors, the p ace where ts reported m ght be some d stance from the actua ocat on of the
error

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

314Microsoft Visual C++/CLI Step by Step

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

Parsing XML with validation


There are a number of ways to va date the correctness of XML documents, and XmlReader supports
the two most common standards DTDs and W3C schemas
The fo ow ng exerc se mod fies the app cat on to va date the XML as ts parsed To perform va dat on, you need to have a DTD or a schema aga nst wh ch to va date Heres a DTD for the vo cano
XML data (th s s n a fi e named geo ogy dtd)
<!ELEMENT
<!ELEMENT
<!ATTLIST
<!ELEMENT
<!ELEMENT
<!ATTLIST
<!ELEMENT
<!ELEMENT
<!ELEMENT
<!ELEMENT

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.

Chapter 17 Read ng and wr t ng XML 315

Ed t the vo canoes xm fi e to add a DOCTYPE reference at the top of the fi e


<?xml version="1.0" ?>
<!DOCTYPE geology SYSTEM "geology.dtd">
<!-- Volcano data -->

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

do not set th s, pars ng w

fa because the defau t sett ng proh b ts DTD pars ng

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

e ement order ng n the document


The element 'volcano' has invalid child element 'type'. List of possible elements
expected: 'height'.

316Microsoft Visual C++/CLI Step by Step

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

stat c hand er funct on Add th s code before the main funct on


// Validation handler class
ref class ValHandler
{
public:
static void ValidationHandler(Object ^sender, ValidationEventArgs ^args)
{
Console::WriteLine("Validation Event: {0}", args->Message);
}
};

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

shou dnt see any va dat on messages th s t me through

Chapter 17 Read ng and wr t ng XML 317

Writing XML by using XmlTextWriter


If youve read about XML, youre probab y aware that the W3C XML 1 spec ficat on descr bes the
ser a zed form of XMLthe way that XML appears when rendered as textcomp ete w th ang e
brackets, start tags and end tags, and namespace and XML dec arat ons If you have some data that
you want to wr te as XML, t snt hard to do t manua y, but the NET Framework prov des you w th
the XmlTextWriter c ass to he p w th a ot of the formatt ng chores such as keep ng track of ndentat on and nsert ng namespace nformat on everywhere ts needed The tab es that fo ow st the
propert es and methods of the XmlTextWriter class, respectively
Property

Description

BaseStream

Gets the under y ng stream object

Formatting

Determ nes whether the XML s output w th ndentat on.


The defau t s Formatting::None.

Indentation

Determ nes the ndentat on eve . The defau t s 2.

IndentChar

Represents the ndentat on character. The defau t s a


space.

Namespaces

Determ nes whether to support namespaces. The defau t


s true.

QuoteChar

Represents the character used to quote attr bute va ues.


The va ue must be a s ng e or doub e quotat on mark. The
defau t s doub e.

Settings

Gets the XmlWriterSettings object used when crea ng th s


XmlWriter nstance

WriteState

Gets the state of the wr ter (d scussed n the fo ow ng


text).

XmlLang

Gets a str ng that represents the va ue of the xml:lang


attr bute. The va ue w be nu f there s no xml:lang
attr bute n the current scope.

XmlSpace

Represents the va ue of the xml:space attr bute.

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

C oses the wr ter and the under y ng stream

Flush

F ushes whatever s n the buffer

LookupPrefix

Returns the current namespace prefix, f any

WriteAttributes

Wr tes out a set of attr butes

WriteAttributeString

Wr tes an attr bute w th a spec fied va ue

WriteBase64, WriteBinHex

Encodes b nary bytes as Base64 or B nHex, and wr tes the


text

318Microsoft Visual C++/CLI Step by Step

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

to create the XmlReader n the prev ous exerc se)


try
{
// Create the writer...
// Use the default encoding
XmlTextWriter ^writer = gcnew XmlTextWriter(path, nullptr);
}
catch (Exception ^ex)
{
Console::WriteLine(ex->Message);
}

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

ns de the try b ock


// Set the formatting
writer->Formatting = Formatting::Indented;
// Write the standard document start
writer->WriteStartDocument();
// Flush and close
writer->Flush();
writer->Close();

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

7. The content of the root e ement w

go between the ca s to WriteStartElement and


WriteEndElement There snt any content n th s case, but you st need both ca s Bu d
and run the app cat on at th s stage, g v ng the name of the XML fi e

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

entr es to the root e ement, as

ustrated n the fo ow ng

// Start the root element


writer->WriteStartElement("geology");
// Start the volcano element
writer->WriteStartElement("volcano");
// Do the name attribute
writer->WriteAttributeString("name", "Mount St.Helens");
// Write the location element
writer->WriteStartElement("location");
writer->WriteString("Washington State, USA");
writer->WriteEndElement();
// Write the height element
writer->WriteStartElement("height");
writer->WriteAttributeString("value", "9677");
writer->WriteAttributeString("unit", "ft");
writer->WriteEndElement();
// Write the type element
writer->WriteStartElement("type");
writer->WriteString("stratovolcano");
writer->WriteEndElement();

Chapter 17 Read ng and wr t ng XML 321

// Write the eruption elements


writer->WriteStartElement("eruption");
writer->WriteString("1857");
writer->WriteEndElement();
writer->WriteStartElement("eruption");
writer->WriteString("1980");
writer->WriteEndElement();
// Write the magma element
writer->WriteStartElement("magma");
writer->WriteString("basalt, andesite and dacite");
writer->WriteEndElement();
// Close the volcano element
writer->WriteEndElement();
// Close the root element
writer->WriteEndElement();

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

XML that ooks very much ke th s


<?xml version="1.0"?>
<geology>
<volcano name="Mount St.Helens">
<location>Washington State, USA</location>
<height value="9677" unit="ft" />
<type>stratovolcano</type>
<eruption>1857</eruption>
<eruption>1980</eruption>
<magma>basalt, andesite and dacite</magma>
</volcano>
</geology>

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

322Microsoft Visual C++/CLI Step by Step

5. Add a constructor that creates an XmlDocument object, and nstruct t to oad the fi e that was

spec fied on the command ne


public:
XmlBuilder(String ^path)
{
// Create the XmlDocument
doc = gcnew XmlDocument();
// Load the data
doc->Load(path);
Console::WriteLine("Document loaded");
}

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-

pared to hand e any except ons that occur


// Create a Builder and get it to read the file
try
{
XmlBuilder ^builder = gcnew XmlBuilder(path);
}
catch(Exception ^ex)
{
Console::WriteLine(ex->Message);
}

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;

328Microsoft Visual C++/CLI Step by Step

9. Add the fo ow ng code to the constructor to get the root node


// Get the root of the tree
root = doc->DocumentElement;

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,

add an XmlNodeList^ member to the c ass to ho d the st


private:
XmlNodeList ^nodelist;

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 ChildNodes property returns a st of ch d nodes as an XmlNodeList The XmlNodeList s a


typ ca NET co ect on c ass, wh ch means that you can get an enumerator to terate over the
nodes The code terates over the ch d nodes, pr nt ng the name of each Note that because
Current returns an Object hand e, t has to be cast to an XmlNode^ before you can use the
Name property
12. The IEnumerator nterface s part of the System::Collections namespace, so you need to add

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!

Chapter 17 Read ng and wr t ng XML 329

14. Now that you have the root of the tree, you need to find the root e ement of the XML by us-

ng a pub c c ass member funct on named ProcessChildNodes, as shown here


void ProcessChildNodes()
{
// Declare an enumerator
IEnumerator ^ie = nodelist->GetEnumerator();
while (ie->MoveNext() == true)
{
// Get a handle to the node
XmlNode ^node = dynamic_cast<XmlNode^>(ie->Current);
// See if it is the root
if (node->NodeType == XmlNodeType::Element &&
node->Name->Equals("geology"))
{
Console::WriteLine(" Found the root");
ProcessRoot(node);
}
}
}

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 ch dren of the root XML e ement


void ProcessRoot(XmlNode ^rootNode)
{
XmlNode ^node =
dynamic_cast<XmlNode^>(rootNode->ChildNodes->Item(1));
// Create a new volcano element
XmlElement ^newVolcano = CreateNewVolcano();
// Link it in
root->InsertBefore(newVolcano, node);
}

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

330Microsoft Visual C++/CLI Step by Step

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

PrintTree to the c ass, as shown here


void PrintTree()
{
XmlTextWriter ^xtw = gcnew XmlTextWriter(Console::Out);
xtw->Formatting = Formatting::Indented;
doc->WriteTo(xtw);
xtw->Flush();
Console::WriteLine();
}

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

Chapter 17 Read ng and wr t ng XML 331

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

Parse XML w thout va dat on.

Create an XmlReader, and pass t the name of a fi e. Then,


use the Read method to read nodes from the fi e.

Parse XML w th DTD va dat on.

Create an XmlReaderSettings object, and set ts


ValidationType property to ValidationType::DTD.
You must a so set the DtdProcessing property to
DtdProcessing::Parse.
Then, use the sett ngs to n t a ze an XmlReader. Create a
hand er funct on for va dat on events and attach t to the
ValidationEventHandler event of the XmlReader.

Work w th XML n memory.

Create an XmlDocument and use ts Load or LoadXml


funct on to parse XML nto a DOM tree n memory.

332Microsoft Visual C++/CLI Step by Step

CHAPTER 18

Using ADO.NET
After comp et ng th s chapter, you w

be ab e to

Connect to a database

Execute SQL statements to query the database

Execute SQL statements to update the database

Create d sconnected app cat ons, wh ch use a DataSet to cache tab es n memory

Create a report d sp ay ng data from the database

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

ADO.NET data providers


ADO NET uses the concept of a data prov der to fac tate effic ent access to d fferent types of
databases Each data prov der nc udes c asses to connect to a part cu ar type of database The
NET Framework nc udes s x data prov ders, as shown n the fo ow ng tab e
Data provider

Description

System.Data.SqlClient

Conta ns c asses that g ve opt m zed access to SQL


Server7 and ater

System.Data.OleDb

Conta ns c asses that g ve access to SQL Server 6.5 and


ear er; a so prov des access to databases such as Orac e,
Sybase, Access, and so on

System.Data.ODBC

Conta ns c asses that g ve access to Open Database


Connect v ty (ODBC) data sources

System.Data.OracleClient

Conta ns c asses that g ve access to Orac e databases

System.Data.EntityClient

Conta ns c asses that support the Ent ty Framework


(d scussed n Chapter 24, L v ng w th COM)

System.Data.SqlServerCe

Conta ns c asses that work w th SQL Server Compact


Ed t on

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

334Microsoft Visual C++/CLI Step by Step

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>

// This assembly contains ADO.NET classes


// This assembly contains the
// Entity Framework provider classes

Note If you are creating projects by using Microsoft Visual Studio 2012, the reference to
System.Data.dll will be provided for you.

Referencing external assemblies


If you want to use a type defined n another assemb y, both the comp er and the runt me need
to know where that assemb y s ocated You m ght want to reference types from a Common
Language Runt me (CLR) brary assemb y, from a th rd-party brary assemb y, or even from
another assemb y that youve created n the same so ut on You can add references to a these
types of assemb y n the same way
On the Project menu, c ck 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 Framework And References At the
bottom of the w ndow, c ck the Add New Reference button In the Add Reference d a og box
that opens, n the pane on the eft pane, c ck one of the opt ons For examp e, se ect ng Assemb es and then Framework d sp ays a the CLR brary assemb es for you to browse Se ect
the entry you requ re and then press OK tw ce to d sm ss both d a og boxes If you now expand
the Externa Dependenc es tem n So ut on Exp orer, you w see the new dependency n the
st

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;

Creating a connected application


In the next few pages, you w create a C++/CLI app cat on that connects to an Access database You
w see how to set up the database connect on and prov der deta s n the app cat on configurat on
fi e and then use a DbConnection object to estab sh a connect on

336Microsoft Visual C++/CLI Step by Step

After you are connected, you w create a DbCommand object to represent a SQL statement You
then perform the fo ow ng tasks

Use the ExecuteScalar method on DbCommand to execute a statement that returns a s ng e


va ue
Use the ExecuteNonQuery method on DbCommand to execute a statement that updates the
database
Use the ExecuteReader method to execute a statement that quer es the database Execute
Reader returns a DbDataReader object, wh ch prov des fast, forward-on y access to the rows
nthe resu t set You w use th s DbDataReader object to process the resu t set

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

Chapter 18 Us ng ADO.NET 337

Application configuration files


An app cat on can have an XML configurat on fi e whose name cons sts of the name of the app cat on w th a .config extens on, and wh ch s ocated n the same d rectory as the executab e
For examp e, an app cat on ca ed MyApp.exe wou d have a configurat on fi e ca ed MyApp.exe.
config
The app cat on configurat on fi e conta ns sett ngs spec fic to an app cat on These sett ngs
m ght overr de or add to computer- eve configurat on sett ngs The configurat on fi e can a so
be used to store configurat on nformat on such as connect on str ngs and error messages
You can add a configurat on fi e to a project and ed t t to add the appropr ate sett ngs
When the project s bu t, the configurat on fi e needs to be renamed to nc ude the executab e
name, and cop ed to the output d rectory
Unfortunate y, V sua Stud o 2012 does not perform th s copy ng and renam ng automat ca y when bu d ng a C++ project You can, however, add th s as a custom bu d step to your
project Open the Project Propert es d a og box and choose Configurat on Propert es Then,
n the co umn on the eft, c ck Bu d Events And Post-Bu d Event Ed t the Command entry to
read as fo ows
copy app.config "$(TargetPath).config"

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

4. Ed t the app config fi e to add a connect on str ng


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings>
<clear/>
<add name="Blog"
connectionString=
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\path\to\blog.mdb"
providerName="System.Data.OleDb" />
</connectionStrings>
</configuration>

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

5. To work w th configurat on fi es, you need to add a reference to System.Configuration.dll Do th s

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");
}

Chapter 18 Us ng ADO.NET 339

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

Creating and executing a command


In th s exerc se, you w

create a DbCommand object that represents the fo ow ng SQL statement

SELECT COUNT(*) FROM Entries

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-

1. Cont nue w th the project from the prev ous exerc se


2. In the main funct on, add the fo ow ng code to the try b ock, after the statement that opens

the database connect on


// Count the entries
DbCommand ^cmd = fac->CreateCommand();
cmd->CommandText = "SELECT COUNT(*) FROM Entries";
cmd->CommandType = CommandType::Text;
cmd->Connection = conn;

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

4. Bu d your app cat on and fix any comp er errors


5. Run the app cat on

The message shown n the fo ow ng figure shou d appear on the conso e

Executing a command that modifies data


In th s exerc se, you w

add a new entry nto the database by us ng the fo ow ng SQL statement

INSERT INTO [Entries] ([Date], [Text], [Author])


VALUES ('Dec 02, 2012', 'Some text', 'Julian')

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')";

Chapter 18 Us ng ADO.NET 341

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

4. Bu d your app cat on and fix any comp er errors


5. Run the app cat on

The message shown n the fo ow ng figure shou d appear on the conso e

Executing queries and processing the results


In the fina part of th s connected app cat on exerc se, you w execute a command that retr eves
nformat on from the database by us ng the fo ow ng SQL statement
SELECT * FROM Entries

You w use the ExecuteReader method to execute th s statement Th s w return a DbDataReader


object, wh ch s a fast, forward-on y reader that reads through each row n the resu t set n turn
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
// Query the database
cmd->CommandText = "SELECT * FROM Entries";

342Microsoft Visual C++/CLI Step by Step

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

6. Run the app cat on

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 )

Chapter 18 Us ng ADO.NET 343

Creating a disconnected application


For the rest of the chapter, we turn our attent on to d sconnected app cat ons A d sconnected
app cat on s one that does not have a permanent y ava ab e connect on to the data source App cat ons are much more sca ab e when they on y need a database connect on to retr eve or send data
back, and t s poss b e for an app cat on such as a webs te to support many users w th on y a handfu
of database connect ons
In ADO NET, the DataSet c ass represents a d sconnected, oca data store The fo ow ng figure
shows the DataSet object mode

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

344Microsoft Visual C++/CLI Step by Step

The fo ow ng figure shows how data adapters work w th DataSets

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

Conta ns a SQL SELECT statement to retr eve data from


the database nto the DataSet tab e

InsertCommand

Conta ns a SQL NSERT statement to nsert new rows from


the DataSet tab e nto the database

UpdateCommand

Conta ns a SQL UPDATE statement to mod fy ex st ng


rows n the database

DeleteCommand

Conta ns a SQL DELETE statement to de ete rows from the


database

Disconnected operation using a DataSet


Th s exerc se shows you how to create a DataSet, fi t by us ng a DataAdapter, and extract data from
the tab es n the DataSet The deta s of sett ng up the configurat on and gett ng a connect on are
exact y the same as for the prev ous exerc se, so you w be ab e reuse a ot of the code
1. Start a new CLR Conso e project project named DataSetApp
2. Add an externa reference to the System::Configuration assemb y by us ng the Propert es d a-

og box, as deta ed n the s debar Referenc ng externa assemb es ear er n the chapter

Chapter 18 Us ng ADO.NET 345

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-

p cat on Here s the content that you need


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings>
<clear/>
<add name="Blog"
connectionString=
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\path\to\blog.mdb"
providerName="System.Data.OleDb" />
</connectionStrings>
</configuration>

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

346Microsoft Visual C++/CLI Step by Step

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

to be retr ev ng data, you on y need to set the Select command Do th s by creat ng a


DbCommand object, as n the prev ous exerc se, and then ass gn ng t to the SelectCommand
property of the adapter
DbCommand ^cmd = fac->CreateCommand();
cmd->CommandText = "SELECT * FROM Entries";
cmd->CommandType = CommandType::Text;
cmd->Connection = conn;
adapter->SelectCommand = cmd;

11. You can now create a DataSet and ask the adapter to fi

DataSet ^dataset = gcnew DataSet("Blog");


adapter->Fill(dataset, "Entries");

The first ne creates an empty DataSet ca ed B og Ca ng Fill on the adapter causes t to


execute ts SelectCommand, wh ch creates a DataTable ca ed Entr es, fi s t w th the resu t of
the query, and then adds t to the DataSets co ect on of DataTables

Chapter 18 Us ng ADO.NET 347

G v ng names to DataSets and DataTables s opt ona , but as you w


fu when bu d ng XML documents from DataSet data

see short y, t s very use-

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

first few nes ook ke th s


<Blog>
<Entries>
<ID>2</ID>
<Date>Jul 01, 2009</Date>

348Microsoft Visual C++/CLI Step by Step

<Text>A first entry</Text>


<Author>Julian</Author>
</Entries>
<Entries>
<ID>3</ID>
<Date>Jun 27, 2009</Date>
<Text>Second entry</Text>
<Author>Julian</Author>
</Entries>
...

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

Chapter 18 Us ng ADO.NET 349

Quick reference
To

Do this

Use ADO.NET c asses.

f you are us ng V sua Stud o 2012, you w need to add


on y a us ng d rect ve for the appropr ate assemb es. For
examp e:
using namespace System::Data;
using namespace System::Data::Common;

Store connect on str ngs n the app cat on configurat on


fi e.

Add an app cat on configurat on fi e to the project, and


add a post bu d event to rename t:
copy app.config $(TargetPath).config

Then, add one or more connect on str ng sect ons to the


.config fi e. For examp e:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings>
<add name="NWind"
connectionString=
"Provider=Microsoft.Jet.OLEDB.4.0;"
"Data Source=C:\SbS\Blog.mdb"
providerName="System.Data.OleDb" />
</connectionStrings>
</configuration>

Connect to a database.

Obta n the prov der factory by us ng the prov der name.


For examp e:
DbProvideFactory ^factory =
DbProviderFactories::GetFactory(name);

Then create a DbConnection object, and configure ts


ConnectionString property. For examp e:
DbConnection ^conn = factory->CreateConnection();
conn->ConnectionString = connString;

Create a SQL command.

Create a DbCommand object and configure ts


CommandText, CommandType, and Connection propert es.

Execute a command.

f the command returns a sca ar va ue, ca ExecuteScalar.


f the command mod fies the database, ca Execute
NonQuery. f the command performs a query, ca
ExecuteReader. Ass gn the resu t to a DbDataReader
object and use th s reader to oop through the resu t set.
For examp e:
DbDataReader ^reader = cmd->ExecuteReader();
while (reader->Read())
{
Console::Write(reader->GetString(0));
}

Use data n a d sconnected app cat on.

Create a DbDataAdapter, add DbCommands to access


the database, and then set ts connect on. Create a
DataSet and fi the DataSet by us ng the data adapter. For
examp e:
DbDataAdapter ^daTitles =
factory->CreateDataAdapter();
daTitles->SelectCommand = cmd;
daTitles->Connection = conn;
DataSet^ ds = gcnew DataSet("Titles");
daTitles->Fill(ds);

350Microsoft Visual C++/CLI Step by Step

CHAPTER 19

Writing a service by using


Windows Communication
Foundation
After comp et ng th s chapter, you w

be ab e to

Descr be what W ndows Commun cat on Foundat on s

Wr te serv ces by us ng W ndows Commun cat on Foundat on

Wr te c ents to use W ndows Commun cat on Foundat on serv ces

What is Windows Communication Foundation?


W ndows Commun cat on Foundat on (WCF) s M crosofts p atform for wr t ng d str buted, serv cebased app cat ons Prev ous y known as Ind go, t prov des a framework for wr t ng serv ces and
c ents

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

352Microsoft Visual C++/CLI Step by Step

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

The ABCs of WCF


WCF conta ns a ot of deta a ot of mov ng partsand t s very easy to ose s ght of what s mportant n a mass of deta There s, however, a certa n number of th ngs that you need to know to work
w th WCF, and so n th s sect on I present enough deta s on how WCF works and what t does that
you w be ab e to wr te and consume a s mp e serv ce, and apprec ate other features of WCF that you
m ght want to use n future projects

Endpoints
A serv ce n WCF s ca ed an endpoint Endpo nts are character zed by three facets

Address Where to find the serv ce

Binding How to ta k to the serv ce

Contract What the serv ce can do

Chapter 19 Wr t ng a serv ce by us ng W ndows Commun cat on Foundat on 353

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

Service contracts A serv ce contract exposes a NET c ass or nterface as a serv ce


Operation contracts An operat on contract exposes a method on a type as a serv ce (You
can on y make methods nto operat ons, not propert es)
Data contracts A data contract s used to nstruct WCF how to use custom types n serv ce
ca s WCF knows about a range of bas c types, such as numbers and str ngs, but f you want
to use a Person type as an operat on parameter or return type, WCF w need to know what a
Person object conta ns
Fault contracts A fau t contract s used to define error behav or

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.

356Microsoft Visual C++/CLI Step by Step

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.

Message exchange patterns


Commun cat on between c ents and serv ces can be one-way or b -d rect ona WCF supports three
message exchange patterns (MEPs) that govern how c ents commun cate w th serv ces

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

Chapter 19 Wr t ng a serv ce by us ng W ndows Commun cat on Foundat on 357

Examp es of behav ors nc ude

How serv ce objects are created Is there just one or s there a new object created per ca ?

How the serv ce hand es concurrent ca s

L m t ng the number of s mu taneous connect ons

Hand ng transact ons

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

dec arat ons


using namespace System::ServiceModel;
using namespace System::ServiceModel::Channels;

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

Chapter 19 Wr t ng a serv ce by us ng W ndows Commun cat on Foundat on 359

Include files and the preprocessor


You m ght not have encountered th s use of the preprocessor before One of the prob ems w th
nc ude fi es s that, n comp ex code, you can end up w th mu t p e nc us ons Suppose that
youve wr tten A h to nc ude B h and C h, and that both of those nc ude D h That fi e w be
nc uded tw ce, and you probab y get errors due to mu t p e defin t ons
Th s usua y happens deep y nested n a tree of nc ude fi es, and t can be a hass e to sort
out The recommended way around t s to use an include guard, such as the one defined n
the prev ous examp e The first ne says that f the preprocessor symbo IMATHSERVICE H s
not defined, nc ude the contents of the fi e up unt the #endif The second ne then defines
the symbo , and th s means that f another attempt s made to nc ude the same fi e w th n th s
comp at on, the first #ifndef w fa and the code wont be nc uded
You can make the symbo just about anyth ng you ke, but t s common to base t on the
name of the nc ude fi e to avo d any poss b e dup cat on, and t s convent on to define symbo s n cap ta s

4. Open the MathServ ce cpp fi e and add the defin t on for a c ass that mp ements the serv ce

You need to add an include statement to get the nterface defin t on


#include "IMathService.h"
ref class MathService : IMathService
{
public:
virtual double Square(double d)
{
return d*d;
}
virtual double Cube(double d)
{
return d*d*d;
}
};

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

360Microsoft Visual C++/CLI Step by Step

6. Create a ServiceHost object and add an endpo nt to t


ServiceHost ^host = gcnew ServiceHost(MathService::typeid, baseAddress);
host->AddServiceEndpoint(IMathService::typeid, binding, baseAddress);

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

Writing a service client


The next step s obv ous y to wr te a c ent to test out the serv ce There s a WCF Test C ent nc uded
w th V sua Stud o, but you wont be ab e to use that unt youve added metadata support to the
serv ce, and we w eave that unt ater n the chapter
1. Create another CLR Conso e App cat on named TestClient

Chapter 19 Wr t ng a serv ce by us ng W ndows Commun cat on Foundat on 361

2. In W ndows Exp orer, copy the IMathServ ce h fi e to the project d rectory and add t to the

project R ght-c ck the project name On the shortcut menu, po nt to Add, po nt to Ex st ng


Item, and then c ck the header fi e
You need to add th s fi e because your c ent code needs the defin t on of the nterface
3. Add an externa reference to the System::ServiceModel assemb y, just ke you d d when creat-

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

9. When youre done, c ose the channe


((IChannel^)channel)->Close();

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

362Microsoft Visual C++/CLI Step by Step

Adding metadata to the service


One of the character st cs of serv ces s that they are d scoverab e Th s means that there s some way
for potent a c ents to get deta s of the serv ce, what t can do and how to ca t The standard way to
prov de th s metadata s as a WSDL document, wh ch descr bes the serv ce n XML

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

Chapter 19 Wr t ng a serv ce by us ng W ndows Commun cat on Foundat on 363

4. Bu d the project and then start the serv ce as adm n strator


5. Start Internet Exp orer and type the fo ow ng URL n the address bar
http://localhost:8080/MathService?wsdl

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/

MathService) nto the text box and press OK


After a short nterva , you shou d see deta s of the serv ce contract appear n the pane on the
eft n the WTF Test C ent app cat on w ndow

364Microsoft Visual C++/CLI Step by Step

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

Accessing a service by using a proxy


You have seen how to connect to a serv ce manua y by us ng the WCF APIs It s a so poss b e to get
V sua Stud o to create a proxy c ass for you, one that encapsu ates the deta s of where the serv ce s
and what the endpo nts are; n th s way, you dont have to be concerned w th the ow- eve mechan cs
Th s s often the way that you wou d do t n C# and M crosoft V sua Bas c NET, ask ng V sua Stud o to add a serv ce reference to your project, and then us ng the generated proxy c ass The prob em
s that th s feature snt supported by C++/CLI n V sua Stud o, but t turns out to be qu te s mp e to do
f you use a C# wrapper

Creating the wrapper DLL


In th s next exerc se, you w create a s mp e C# Dynam c-L nk L brary (DLL) project and add a reference to the MathServ ce project Th s w add a proxy c ass to the project, but because t s a pub c
c ass, you w be ab e to use t from C++/CLI code And even though you create a C# project, you
dont have to wr te a s ng e ne of C# n order to make t work

Chapter 19 Wr t ng a serv ce by us ng W ndows Commun cat on Foundat on 365

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,

and then, on the shortcut menu, c ck Add Serv ce Reference


4. In the Add Serv ce Reference d a og box that opens, type the URL of the serv ce nto the ad-

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

generate a proxy c ass and app cat on configurat on fi e for you

6. You dont need to add anyth ng e se to th s project, so just bu d t to create the DLL

Using the wrapper


You now have a DLL that conta ns a the code necessary to ca MathServ ce In the second part of the
exerc se, you see how to use th s DLL n a C++/CLI app cat on
1. Create a CLR Conso e App cat on project named TestWcf

366Microsoft Visual C++/CLI Step by Step

2. Add an externa reference to System::ServiceModel.


3. Add a second externa reference to the WcfC entL b DLL, wh ch you find n the WcfC entL b/

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

and copy the <system.ServiceModel> e ement shown here


<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="WSHttpBinding_IMathService" />
</wsHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:8080/MathService" binding="wsHttpBinding"
bindingConfiguration="WSHttpBinding_IMathService"
contract="ServiceReference1.IMathService"
name="WSHttpBinding_IMathService">
<identity>
<userPrincipalName value="WIN8PREVIEW\Julian" />
</identity>
</endpoint>
</client>
</system.serviceModel>

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

Chapter 19 Wr t ng a serv ce by us ng W ndows Commun cat on Foundat on 367

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

Define a serv ce nterface.

Define an nterface and annotate t w th [ServiceContract].


Annotate the methods on the nterface w th
[OperationContract].

Create a serv ce.

Create a c ass that mp ements the serv ce nterface.

Host a serv ce.

Create a ServiceHost object

Creat ng a serv ce c ent

Create a ChannelFactory and use t to create a channe .


Then, ca methods on the channe .

Expose metadata from a serv ce.

Add the Serv ce Metadata behav or to your serv ce.

Test A WCF serv ce.

Use the the WCF Test C ent.

Access ng a serv ce us ng a proxy c ass.

Create a C# DLL project, and add a reference to the ser


v ce us ng the Add Serv ce Reference d a og.

CHAPTER 20

Introducing Windows Store apps


After comp et ng th s chapter, you w

be ab e to

Exp a n essent a features of the W ndows Store user nterface

Create user nterfaces by us ng XAML

Create, dep oy, and run a s mp e W ndows Store app

Descr be the essent a features of C++/CX

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

A (brief) history of writing Windows user interface


applications
The way n wh ch W ndows user nterface (UI) app cat ons have been wr tten has evo ved over the
years, from the ear est app cat ons wr tten n C, through a move to C++, then M crosoft NET, and
now W ndows 8 Th s sect on g ves you a br ef overv ew and h story and a so prov des nformat on to
he p you dec de wh ch techno ogy you shou d cons der us ng for a UI app cat on

The Win32 API


The ear est W ndows UI app cat ons were usua y wr tten n C by us ng the W n32 API Th s was an
exact ng task, somewhat equ va ent to wr t ng code n assemb y anguage There was a tremendous
amount of bo erp ate code needed to do a most anyth ng, and you had to know just what was go ng
on because there was no h gher- eve brary tak ng care of the housekeep ng for you
For examp e, the s mp e task of creat ng a w ndow on the screen enta ed ca ng a funct on that
took no fewer than 12 parameters, as demonstrated here
HWND WINAPI CreateWindowEx(
DWORD dwExStyle, LPCTSTR lpClassName, LPCTSTR lpWindowName,
DWORD dwStyle, int x, int y, int nWidth, int nHeight,
HWND hWndParent, HMENU hMenu,
HINSTANCE hInstance, LPVOID lpParam);


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

Microsoft Foundation Classes


M crosofts first C++ user nterface brary was M crosoft Foundat on C asses (MFC), n t a y re eased n
1992 and now at vers on 10 MFC prov des a th n C++ wrapper around the W ndow APIs, but t does
perform most of the ted ous housekeep ng for you
MFC made t poss b e to create app cat ons that ooked ke M crosoft Office and W ndows Exp orer, and wh ch cou d nteroperate w th Office app cat ons by us ng a comp ex techno ogy ca ed
Object L nk ng and Embedd ng (OLE) MFC 9 ntroduced a number of new features nc ud ng support
for dock ng w ndows s m ar to those found n M crosoft V sua Stud o, and a r bbon too bar s m ar to
that used n M crosoft Office
MFC has been deprecated n favor of NET, but there are many app cat ons that st use t Vers ons 7 through 9 were des gned to he p deve opers m grate to NET, and so t s regarded as a egacy
framework
One drawback for MFC deve opers s that MFC has never had a UI des gner n V sua Stud o, a though there are ed tors for cons, b tmaps, and other resources

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.

370Microsoft Visual C++/CLI Step by Step

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

Windows Presentation Foundation


Vers on 3 0 of the NET Framework saw the re ease of W ndows Presentat on Foundat on (WPF, codenamed Ava on), wh ch was ntended to bu d on the success of W ndows Forms as we as add extra
funct ona ty M crosoft S ver ght s a subset of WPF for wr t ng components to embed n webpages,
and wh ch prov de the same k nd of funct ona ty as Adobe F ash
A though you can use t to des gn form-based app cat ons, WPF s very d fferent from W ndows
Forms Here are some of the ma n d fferences

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

Windows 8 and Windows Store


A though W ndows 8 fu y supports the fam ar W ndows desktop env ronment, t a so prov des a new
way of wr t ng UI app cat ons W ndows Store apps use a brary ca ed Windows RT (or W nRT) wh ch
prov des a UI brary that s a med at touch dev ces and the sty e of nterface made popu ar by the
Pad and other tab ets It s ca ed W ndows Store because t s env saged that deve opers w create
app cat ons and se them on ne through M crosofts W ndows Store, n common w th the way that
many other mob e p atforms make content ava ab e

Chapter 20 ntroduc ng W ndows Store apps 371

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

Which UI library to choose?


So, wh ch UI brary shou d you choose for your app cat ons? For most deve opers, the cho ce w
come down to W ndows Forms, WPF, or W ndows Store
At th s po nt, W n32 and MFC are rea y egacy techno og es, and there are few t mes when you
wou d cons der start ng a new project us ng e ther of them (a though MFC does have some support
for nteract ng w th Office that the newer brar es dont have)
If your app cat on s go ng to have a trad t ona form-based UI, cons st ng ma n y of text boxes and
buttons, and doesnt need fancy graph cs, an mat on, or med a fi e support, W ndows Forms w be
su tab e You w find everyth ng you need n V sua Stud o, nc ud ng a v sua des gner
If you want a desktop app cat on but w th the advanced features that WPF prov des, that s the
way to go, a though f you are us ng C++, you w have to jump through qu te a few hoops to get
there
And, f you want an up-to-date, tab et-sty e nterface that w su t touch dev ces as we as desktop
computers, cons der W ndows Store Oh, and dont et anyone te you that W ndows Store rep aces
WPF; they are des gned for d fferent types of app cat on I cant see anyone produc ng a W ndows
Store-sty e vers on of V sua Stud o any t me soon!

Introducing Windows Store apps


The W ndows Store UI br ngs a comp ete y new sty e of user nterface to W ndows app cat ons Many
of the ways n wh ch UIs have been constructed s nce the first vers ons of W ndows are no onger
supported For examp e, n the W ndows Store UI, there are no menus or d a og boxes, so how do you
et users make cho ces? And then there are a the new modes of nteract on supported by handhe d
dev ces, such as acce erometers and cameras that users w expect to use
Th s means that you need to get used to new ways of wr t ng app cat ons Of course, f youre new
to wr t ng W ndows UI app cat ons, you w n some ways have an eas er task because you have ess
to un earn
If you read about deve opment w th W nRT, you w hear ta k of the green and b ue stacks Th s
phrase arose from how M crosoft descr bed how W nRT was go ng to fit w th the ex st ng W ndows
deve opment techno og es, and they produced a d agram s m ar to the fo ow ng ustrat on

372Microsoft Visual C++/CLI Step by Step

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

Main features of Windows Store apps


In th s sect on, I st some of the major features of W ndows Store apps If you th nk of an app runn ng on a typ ca tab et dev ce or mob e phone, then you shou d be ab e to apprec ate why these
have been ntroduced

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

Chapter 20 ntroduc ng W ndows Store apps 373

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

Contracts and charms


W ndows 8 apps can work together us ng contracts, wh ch express capab t es (such as search or copy
and paste) n a anguage- ndependent way
Charms are UI e ements that nvoke contracts, and every app has access to five standard charms

The WinRT APIs


API ca s can be d rect or brokered Brokered ca s are those that m ght have secur ty concerns, such as
those that affect data or user sett ngs or use dev ce features They must be dec ared by the app, and
m ght need perm ss on from the user n order to run
W nRT p aces a prem um on app response Part of th s s ach eved by suspend ng apps and ett ng
you resume them qu ck y In add t on, any API ca that m ght take more than 50 m seconds s mp emented as an asynchronous ca so that deve opers are forced to adopt a respons ve cod ng sty e

Writing a Windows Store app


Most peop e w

wr te W ndows Store apps n one of three ways

1. Us ng C# or V sua Bas c NET and a subset of the NET Framework brar es

374Microsoft Visual C++/CLI Step by Step

2. Us ng JavaScr pt and HTML5


3. Us ng C++

We are obv ous y go ng to be concentrat ng on the th rd opt on

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++.

Creating your first Windows Store app


Th s exerc se shows you how to wr te the s mp est of W ndows Store apps, wh ch n th s case cons sts
of a s ng e screen and two contro s In Chapter 21, you see how to add more funct ona ty, but th s w
show you the bas cs Remember that to create and run W ndows Store apps, you need to have V sua
Stud o 2012 nsta ed on W ndows 8 Be aware that you m ght a so be prompted to get a deve oper
cense when you create your first project For more nformat on about deve oper censes, read the
s debar at end of th s exerc se
1. In V sua Stud o 2012, open the New Project d a og box
2. In the pane on the eft, c ck W ndows Store
3. In the center pane, c ck B ank App (XAML), and then name the project HelloXaml
4. In the So ut on Exp orer, open Ma nPage xam

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.

Chapter 20 ntroduc ng W ndows Store apps 375

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

s ze because the defau t s rather sma


You m ght a so want to adjust the font s ze for the TextBlock as we , because the defau t m ght
be too sma when runn ng on a desktop computer You find the font sett ngs under the Text
sect on n the Propert es w ndow
9. To work w th the TextBlock n code, you need to g ve t a name Ensure that the Propert es

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

376Microsoft Visual C++/CLI Step by Step

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

Chapter 20 ntroduc ng W ndows Store apps 377

13. Run the app n the norma way, us ng Ctr +F5

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

378Microsoft Visual C++/CLI Step by Step

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

Examining the project


When you create a W ndows 8 app n V sua Stud o, a ot of fi es are created It s usefu to know
someth ng about what they are, and n part cu ar, wh ch ones you can ed t and wh ch you shou d
eave a one
The fo ow ng fi es are those that you can ed t

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.

Chapter 20 ntroduc ng W ndows Store apps 379

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

App.g.h and App.g.cpp The ma n funct on and XAML oad ng code


StandardStyles.xaml Predefined sty es and temp ates You can der ve from these, but dont
change them
MainPage.g.h and MainPage.g.cpp Generated part a c ass defin t ons for the defau t
page Another pa r of g h and g cpp fi es are added for every page you add to the
app cat on
XamlTypeInfo.g.h Type nformat on generated by the XAML ed tor

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

380Microsoft Visual C++/CLI Step by Step

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

Chapter 20 ntroduc ng W ndows Store apps 381

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

382Microsoft Visual C++/CLI Step by Step

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

Chapter 20 ntroduc ng W ndows Store apps 385

The XAML for th s ayout shows some nterest ng features


<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}" >
<Grid.RowDefinitions>
<RowDefinition Height="60*" />
<RowDefinition Height="40*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="60*" />
<ColumnDefinition Width="40*" />
</Grid.ColumnDefinitions>
<Button Content="First" FontSize="24" Background="Blue" Grid.Row="0"
HorizontalAlignment="Center"/>
<Button Content="Second" FontSize="24" Background="Green" Grid.Row="1"
HorizontalAlignment="Center"/>
<Button Content="Third" FontSize="24" Background="Red" Grid.Column="1" Grid.Row="1"
HorizontalAlignment="Center"/>
</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

386Microsoft Visual C++/CLI Step by Step

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 XAML ooks ke th s


<VariableSizedWrapGrid Background="{StaticResource ApplicationPageBackgroundThemeBrush}"
MaximumRowsOrColumns="3" Orientation="Horizontal" ItemWidth="150">
<Button Content="First" FontSize="24" Background="Blue" HorizontalAlignment="Center"/>
<Button Content="Second" FontSize="24" Background="Green" HorizontalAlignment="Center"/>
<Button Content="Third" FontSize="24" Background="Red" HorizontalAlignment="Center"/>
<Button Content="Fourth" FontSize="24" Background="Cyan" HorizontalAlignment="Center"/>
<Button Content="Fifth" FontSize="24" Background="Magenta" HorizontalAlignment="Center"/>
</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"/>

Chapter 20 ntroduc ng W ndows Store apps 387

<Button Content="Third" FontSize="24" Background="Red" HorizontalAlignment="Stretch"


VerticalAlignment="Stretch"/>
<Button Content="Fourth" FontSize="24" Background="Cyan" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"/>
<Button Content="Fifth" FontSize="24" Background="Magenta" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"/>
</VariableSizedWrapGrid>

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

Heres the XAML for the ayout


<Canvas Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Button Content="First" FontSize="24" Canvas.Left="100" Canvas.Top="100" Background="Blue"/>
<Button Content="Second" FontSize="24" Canvas.Left="150" Canvas.Top="150"
Background="Green"/>
<Button Content="Third" FontSize="24" Canvas.Left="180" Canvas.Top="180" Background="Red" />
</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

388Microsoft Visual C++/CLI Step by Step

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

C++/CX and Windows RT


Wr t ng W ndows Store apps exposes you to yet another var ety of C++, known as C++/CX (Component Extens ons)
You m ght we wonder (as I have myse f on more than one occas on) why M crosoft needed to create yet another set of extens ons to C++ when they had on y recent y ntroduced C++/CLI
The ma n reason for th s s that W ndows Store apps do not use managed code; thus, they do not
make use of the CLR When you wr te a W ndows Store app, t comp es down to nat ve code rather
than IL, so C++/CLI s not appropr ate

Chapter 20 ntroduc ng W ndows Store apps 389

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

MyClass ^mc = ref new MyClass();

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
{
};

If a c ass s go ng to conta n W nRT components, t must be dec ared as a ref class


C++/CX a so ntroduces the concept of partial classes, by wh ch a c ass can be sp t nto more than
one part and comb ned by the comp er Th s s necessary to support XAML, n wh ch the GUI des gner
n V sua Stud o generates code to represent a page The deve oper then creates the second ha f of
the c ass to add UI og c

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:

// use the 'partial' keyword

Chapter 20 ntroduc ng W ndows Store apps 391

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";

Or, you can create one ke th s


wchar_t *txt = L"Second string";
String ^s2 = ref new Platform::String(txt);

392Microsoft Visual C++/CLI Step by Step

Quick reference

To

Do This

Create a s ng e page W ndows Store app.

n the New Project d a og box, n the pane on the eft,


c ck W ndows Store. Then, n the center pane, se ect the
B ank App (XAML) project type.

Add contro s to the page.

Drag contro s from the Too box to the page, or ed t the


XAML d rect y.

Hand e events from contro s.

Doub e c ck the contro to add a hand er for the defau t


event. To add hand ers for other events, use the event st
n the Property ed tor.

Lay out e ements n a row, hor zonta y or vert ca y.

Use a StackPanel conta ner w th the Orientation set


appropr ate y.

Lay out e ements n a gr d

Use a Grid conta ner.

Chapter 20 ntroduc ng W ndows Store apps 395

CHAPTER 21

More about Windows Store apps


After comp et ng th s chapter, you w

be ab e to

Create a more comp ex app by us ng XAML and code-beh nd

Hand e events from a more comp ex user nterface

Use W ndows Store app features, such as app bars

Share content w th other app cat ons

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

Building the basic calculator


The app you be bu d ng dur ng the course of th s chapter s a programmers ca cu ator Th s w
offer the features of a norma ca cu ator, such as ar thmet c operat ons and be ng ab e to save va ues
n memory, but t w a so add some funct ons that are often usefu to programmers There s a ot
that cou d be added, but were go ng to m t the add t ons to the ab ty to work n d fferent number
bases (dec ma , hexadec ma , and b nary) In add t on, programmers ca cu ators often work on y w th
ntegers because they are used to man pu ate addresses, so thats what we do here The screen shot
that fo ows shows how the fin shed app w appear


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

Laying out the number buttons


Our UI s a d out n typ ca ca cu ator sty e, w th a TextBlock at the top to d sp ay the current va ue,
and be ow that, number keys a d out n a gr d

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.

398Microsoft Visual C++/CLI Step by Step

Microsoft Blend for Microsoft Visual Studio


V sua Stud o comes w th a des gn too ca ed B end for V sua Stud o 2012, wh ch prov des
a more des gn-or ented env ronment for creat ng UIs, as opposed to V sua Stud os codeor ented approach B end takes a more v sua approach to UI des gn than V sua Stud o, wh ch
makes t s mp er to create sty es and other graph ca e ements The dea s that des gners can
use B end to create soph st cated ayouts by us ng XAML and then pass them on to deve opers
who can add the og c n code

In th s first exerc se, you w


and text d sp ay

create a project w th a s ng e page, and ay out the number buttons

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.

Chapter 21 More about W ndows Store apps 399

The XAML shou d now ook someth ng ke th s


<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Border BorderBrush="Gray" BorderThickness="2" HorizontalAlignment="Left"
Height="89" Margin="432,48,0,0" VerticalAlignment="Top" Width="731">
<TextBlock x:Name="txtOutput" TextWrapping="Wrap" FontSize="72"
HorizontalAlignment="Left"/>
</Border>
...
</Grid>

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

The XAML ought to ook s m ar to the fo ow ng


<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Border BorderBrush="White" BorderThickness="2" HorizontalAlignment="Left"
Height="100" Margin="431,50,0,0" VerticalAlignment="Top" Width="731">
<TextBlock x:Name="txtOutput" TextWrapping="Wrap" FontSize="72"/>
</Border>
<Button x:Name="btnOne" Content="1" HorizontalAlignment="Left" Margin="431,167,0,0"
VerticalAlignment="Top" Height="108" Width="100" FontSize="72"/>
<Button x:Name="btnTwo" Content="2" HorizontalAlignment="Left" Margin="550,167,0,0"
VerticalAlignment="Top" Height="108" Width="100" FontSize="72"/>
<Button x:Name="btnThree" Content="3" HorizontalAlignment="Left" Margin="669,167,0,0"
VerticalAlignment="Top" Height="108" Width="100" FontSize="72"/>

400Microsoft Visual C++/CLI Step by Step

<Button x:Name="btnFour" Content="4" HorizontalAlignment="Left" Margin="431,294,0,0"


VerticalAlignment="Top" Height="108" Width="100" FontSize="72"/>
<Button x:Name="btnFive" Content="5" HorizontalAlignment="Left" Margin="550,294,0,0"
VerticalAlignment="Top" Height="108" Width="100" FontSize="72"/>
<Button x:Name="btnSix" Content="6" HorizontalAlignment="Left" Margin="669,294,0,0"
VerticalAlignment="Top" Height="108" Width="100" FontSize="72"/>
<Button x:Name="btnSeven" Content="7" HorizontalAlignment="Left" Margin="431,422,0,0"
VerticalAlignment="Top" Height="108" Width="100" FontSize="72"/>
<Button x:Name="btnEight" Content="8" HorizontalAlignment="Left" Margin="550,422,0,0"
VerticalAlignment="Top" Height="108" Width="100" FontSize="72"/>
<Button x:Name="btnNine" Content="9" HorizontalAlignment="Left" Margin="669,422,0,0"
VerticalAlignment="Top" Height="108" Width="100" FontSize="72"/>
<Button x:Name="btnClear" Content="C" HorizontalAlignment="Left" Margin="431,550,0,0"
VerticalAlignment="Top" Height="108" Width="100" FontSize="72"/>
<Button x:Name="btnZero" Content="0" HorizontalAlignment="Left" Margin="550,550,0,0"
VerticalAlignment="Top" Height="108" Width="100" FontSize="72"/>
<Button x:Name="btnEquals" Content="=" HorizontalAlignment="Left" Margin="669,550,0,0"
VerticalAlignment="Top" Height="108" Width="100" FontSize="72"/>
</Grid>

6. Bu d and run the app to check that everyth ng s OK Start t by press ng Ctr +F5 or, on the

Debug menu, c ck Start W thout Debugg ng


The app starts by show ng a gray sp ash screen, and then shows the UI If you move the mouse
around you w see that buttons h gh ght as you move over them, and you can a so press
them, a though noth ng w happen at th s po nt
You can get back to the desktop n severa ways you can e ther go v a the Start screen, use the
A t+Tab key comb nat on, or press W ndows key+X to br ng up a menu from wh ch you can
se ect the desktop

Handling number input


Now that you have a bas c ayout n p ace, you can add the og c beh nd the buttons When the user
presses the number keys, you want to remember what they have pressed and bu d up the number
The eas est way to hand e th s s to rea ze that you dont need the actua number unt you come to
perform an operat on unt that po nt, t can ex st as a str ng on the d sp ay Th s means that hand ng
d g t entry s very s mp e, as out ned n the fo ow ng

Get the current str ng from the TextBlock

Get the d g t character represented by the number key

Add the d g t to the str ng

Put the new str ng nto the TextBlock

The fo ow ng steps mp ement th s og c n a hand er


1. Se ect one of the d g t buttons n the XAML Open the Propert es ed tor by c ck ng the Prop-

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

Chapter 21 More about W ndows Store apps 401

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

Click n the text box and press Enter


Th s causes V sua Stud o to create an empty event hand er Ed t the hand er so that t ends up
ke th s
void ProgCalc::MainPage::NumberButtons_Click(Platform::Object^ sender,
Windows::UI::Xaml::RoutedEventArgs^ e)
{
Button ^btn = (Button^)sender;
String ^digit = (String^)btn->Content;
txtOutput->Text += digit;
}

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

V sua Stud o creates a new hand er for you


7. Imp ement the hand er to c ear the str ng n the d sp ay, ke th s
void ProgCalc::MainPage::ClearButton_Click(Platform::Object^ sender,
Windows::UI::Xaml::RoutedEventArgs^ e)
{
txtOutput->Text = "";
}

8. Bu d and test the app

You shou d now be ab e to enter numbers and c ear the d sp ay


402Microsoft Visual C++/CLI Step by Step

Adding arithmetic operations


Now that the numbers are d sp ay ng correct y, the next step s to add the buttons and og c for the
ar thmet c operat ons When the user presses one of the ar thmet c operat on buttons, t s gna s that
she has fin shed enter ng the first number Th s means that you need to perform the fo ow ng steps

Get the str ng from the d sp ay, convert t to a number, and then store t as the eft operand

Remember wh ch operat on was se ected

C ear the d sp ay and prepare t to accept the r ght operand

Adding the arithmetic buttons


The fo ow ng exerc se mp ements the aforement oned steps
1. Ed t the XAML to add four buttons for the bas c ar thmet c operat ons I p aced them n a ver-

t ca co umn, a ong the r ght s de of the numbers, as

ustrated n the fo ow ng screen shot

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 )

Chapter 21 More about W ndows Store apps 403

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

Getting the number


Now, you need to get the str ng from the TextBlock, convert t to an nteger, and store t for ater use
1. Start by add ng an nteger member to the MainPage c ass n Ma nPage xam h, remember ng

to p ace t n the pr vate sect on


int leftOperand;

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.

404Microsoft Visual C++/CLI Step by Step

Remembering the operation


Whats the best way to remember wh ch operat on has been se ected? The obv ous so ut on s to use
a var ab e to store the operat on, and the fact that we want to choose one of a sma set of va ues
shou d suggest us ng an enum for th s
1. Open the Ma nPage xam h fi e and add the dec arat on for an enum at the top, above the

MainPage c ass dec arat on but st

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

after the ca to InitializeComponent


MainPage::MainPage()
{
InitializeComponent();
currentOp = ArithOp::NONE;
}

4. You can now see wh ch button was pressed Ed t the ArithmeticButtons Click funct on to set

the operat on accord ng y, us ng a cha n of if-else statements


Button ^btn = (Button^)sender;
if (btn == btnPlus) currentOp = ArithOp::PLUS;
else if

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

406Microsoft Visual C++/CLI Step by Step

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

Check that there s someth ng to do If there s no content n the TextBlock or no current


operat on, return

Get the text from the d sp ay and convert t to a number

Perform the ca cu at on, us ng the current operat on

Echo the resu t to the d sp ay

Adding the handler and getting the number


1. In Ma nPage xam , br ng up the propert es for the Equa s button and add a hand er ca ed

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;

3. Get the str ng from the d sp ay and convert t to a number

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

Because th s s a ut ty funct on and doesnt need access to nterna deta s of MainPage, th s


doesnt have to be a member of the MainPage c ass, a though you can make t one f you ke
4. Add the mp ementat on to the Ma nPage xam cpp fi e, as shown n the fo ow ng
int
{



}

ProgCalc::ConvertTextToInt(Platform::String ^str)
int val;
swscanf_s(str->Data(), L"%d", &val);
return val;

Chapter 21 More about W ndows Store apps 407

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

6. Bu d the app and confirm that t st

works as expected

Performing the arithmetic operation


At ast you can add the code to EqualsButton Click to perform the operat on
1. Start by dec ar ng the fo ow ng two var ab es, one to ho d the number current y n the

TextBlock, and another to ho d the resu t


int rightOperand = 0;
int result = 0;

2. Store the content of the TextBlock n the rightOperand var ab e


rightOperand = ConvertTextToInt(txtOutput->Text);

3. Add a sw tch statement that branches based on the operat on


switch(currentOp) {
case ArithOp::PLUS:
result = leftOperand + rightOperand;
break;
...
}

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

Ma nPage xam h, a ong w th a Boo ean member ca ed clearOnNextKey


void Reset();
bool clearOnNextKey;

6. Add the defin t on to the source fi e, as demonstrated here


void ProgCalc::MainPage::Reset()
{
currentOp = ArithOp::NONE;
leftOperand = 0;
clearOnNextKey = true;
}

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;
}

If the flag s set, the TextBlock w

be c eared before proceed ng

8. After youve done that, you can comp ete the equa s hand er, turn ng the resu t nto a str ng

and putt ng t back n the d sp ay

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

Chapter 21 More about W ndows Store apps 409

Testing the calculator


Have you ever had a prob em w th a p ece of software and found yourse f th nk ng d dnt anyone test
th s before they re eased t?
We have a exper enced buggy software that doesnt work proper y or crashes, and t s very annoy ng when the prob em s someth ng bas c that ought to have been caught dur ng deve opment
To avo d nfl ct ng the same frustrat on on your users, now that you have mp emented the bas c og c
for the ca cu ator, you need to test what youve done before proceed ng Th s w ensure that you are
bu d ng on a so d foundat on
When test ng, you shou d start by mak ng a test p an Th s doesnt have to be anyth ng comp ex or
grand, but des gn ng a p an he ps to avo d the prob em of test ng by p ay ng around, when you test
what occurs to you at the t me If you do that, you run the r sk of m ss ng out some v ta area because
t d dnt occur to you
How do you dec de what needs to be tested? Here are severa areas that you need to cons der

Does the bas c funct ona ty work as t shou d?

Does the UI render the resu ts correct y and eg b y?

Does the app hand e m stakes and errors proper y?

Does the UI respond to error cond t ons correct y?

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

Add t on of two numbers

Subtract on of two numbers

Mu t p cat on of two numbers

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

410Microsoft Visual C++/CLI Step by Step

Add t on of two numbers

Subtract on of two numbers

D sp ay of negat ve resu t from subtract on

Mu t p cat on of two numbers

D v s on of two non-zero numbers

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

Add t on of two numbers

Add t on of zero g ves r ght answer

Subtract on of two numbers

D sp ay of negat ve resu t from subtract on


Subtract on of zero g ves r ght answer

Mu t p cat on of two numbers

Mu t p

cat on by zero g ves zero

D v s on of two non-zero numbers

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?

What happens f the user keeps press ng the Equa s button?

Does Equa s hand e an empty d sp ay or no operat on?

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

Chapter 21 More about W ndows Store apps 411

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

Improving the graphics


When you run the app, you see that t appears on the Start screen as a rather bor ng, gray square
w th a wh te cross n the m dd e Th s s the defau t mage supp ed for you, and any ser ous deve oper
s go ng to want to update that to someth ng more eye-catch ng and usefu But first, ets ta k about
t es Anyone who has worked w th a computer s comp ete y fam ar w th consthose tt e square
graph cs that are used to represent and start app cat ons W ndows 8 has taken the usefu ness of
cons to a new eve by ntroduc ng t es
By defau t, t es are 150x150 p xe s n s ze, but f the app needs to show more nformat on, t can
use a w de t e that s 310x150 p xe s

Creating and using a tile


Doub e-c ck the Package.appxmanifest fi e to open the man fest ed tor The man fest conta ns deta s
of the resources used by the app and s arranged on four tabs The App cat on UI tab s the one n
wh ch were nterested Th s s where you spec fy deta s of UI e ements such as the t es and sp ash
screen

412Microsoft Visual C++/CLI Step by Step

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 standard 150x150-p xe square ogo

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

Chapter 21 More about W ndows Store apps 413

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

414Microsoft Visual C++/CLI Step by Step

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

Updates and badges


A though we dont have the space here to de ve nto everyth ng that you can do w th t es,
there are two features that are worth ment on ng n pass ng
The first s updat ng In a more trad t ona operat ng system, program cons are norma y
stat c However, n W ndows 8, M crosoft ntroduced the concept of Live tiles W th L ve t es,
not on y can you tap them to start the app, just ke ord nary desktop cons, but they can a so
d sp ay ve content when the app snt runn ng For examp e, the t e for a weather app cou d
d sp ay the current temperature and a weather symbo , or an ema app cou d show how many
new messages have arr ved Programs can update the r own t es, but they are most usefu
because they can be updated by background processes even when the app snt runn ng Th s
means that the Start screen s now a dynam c env ronment, w th app t es reflect ng current
content
The second tem s badges Badges are sma cons that d sp ay not ficat ons n the owerr ght corner of a t e, as shown n the fo ow ng

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

Chapter 21 More about W ndows Store apps 415

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

the ma n d sp ay G ve t a name (such as txtBase) and set ts font s ze to about 24


5. Open the Propert es ed tor, and add a hand er ca ed BaseButtons Click to a three buttons

Changing the base


Add ng the og c for chang ng the number base requ res carefu cons derat on Heres what you need
to do whenever the user c cks one of the base buttons

Set the base to the appropr ate va ue b nary, dec ma , or hexadec ma


Ensure that on y the appropr ate number buttons are enab ed In other words, when n b nary
mode, on y the 0 and 1 keys are enab ed, n dec ma mode 0 through 9 are enab ed,
and n hexadec ma mode the A through F keys are ava ab e, as we

Convert the str ng n the d sp ay to appear n the correct form

Change the sma TextBlock to d sp ay wh ch base s be ng used

The fo ow ng exerc se shows you how to mp ement th s og c


1. You need a way to store the base that has been chosen L ke the ar thmet c operat on, you are

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

n the Reset funct on


// In MainPage.xaml.h
Base base;

418Microsoft Visual C++/CLI Step by Step

// In MainPage.xaml.cpp
void ProgCalc::MainPage::Reset()
{
currentOp = ArithOp::NONE;
base = Base::DEC;
leftOperand = 0;
clearOnNextKey = true;
}

3. Ed t BaseButtons Click and add the out ne of the og c


void ProgCalc::MainPage::BaseButtons_Click(Platform::Object^ sender,
Windows::UI::Xaml::RoutedEventArgs^ e)
{
// Get the button that was pressed
Button ^btn = (Button^)sender;
if (btn == btnDecimal)
{
// Enable the decimal buttons
base = Base::DEC;
txtBase->Text = "dec";
}
else if (btn == btnHex)
{
// Enable the hex buttons
base = Base::HEX;
txtBase->Text = "hex";
}
else if (btn == btnBinary)
{
// Enable the binary buttons
base = Base::BIN;
txtBase->Text = "bin";
}
}

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

Chapter 21 More about W ndows Store apps 419

5. Imp ement the fo ow ng funct ons n Ma nPage xam cpp


void ProgCalc::MainPage::EnableHexButtons(bool enable)
{
btnHexA->IsEnabled = enable;
btnHexB->IsEnabled = enable;
btnHexC->IsEnabled = enable;
btnHexD->IsEnabled = enable;
btnHexE->IsEnabled = enable;
btnHexF->IsEnabled = enable;
}
void ProgCalc::MainPage::EnableBinaryButtons()
{
EnableHexButtons(false);
EnableDecimalButtons(false);
btnZero->IsEnabled = true;
btnOne->IsEnabled = true;
}
void ProgCalc::MainPage::EnableDecimalButtons(bool enable)
{
btnZero->IsEnabled = enable;
btnOne->IsEnabled = enable;
btnTwo->IsEnabled = enable;
btnThree->IsEnabled = enable;
btnFour->IsEnabled = enable;
btnFive->IsEnabled = enable;
btnSix->IsEnabled = enable;
btnSeven->IsEnabled = enable;
btnEight->IsEnabled = enable;
btnNine->IsEnabled = enable;
}

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";
}

420Microsoft Visual C++/CLI Step by Step

else if (btn == btnHex)


{
// Enable the hex buttons
EnableDecimalButtons(true);
EnableHexButtons(true);
base = Base::HEX;
txtBase->Text = "hex";
}
else if (btn == btnBinary)
{
// Enable the binary buttons
EnableBinaryButtons();
base = Base::BIN;
txtBase->Text = "bin";
}

7. Add the defau t state to the Reset funct on so that t w

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

8. Ca Reset from the OnNavigatedTo funct on, wh ch means the page w

n t a ze proper y

9. Bu d the app to ensure there are no cod ng errors

Converting the string in the display


At th s po nt, you can use the buttons to change the number base, but t snt affect ng the va ue
shown on the d sp ay You need to mp ement the base hand er so that t works ke th s

Get the str ng from the d sp ay and convert t to a va ue, us ng the current number base

Change the base, accord ng to wh ch button was pressed

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

Chapter 21 More about W ndows Store apps 421

1. Ed t the ConvertTextToInt funct on so that t ooks ke the fo ow ng examp e Not ce how t s

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

3. Add the mp ementat on to the Ma nPage xam cpp fi e


unsigned long ProgCalc::FromBinary(std::wstring s)
{
wchar_t *stop;
long l = wcstol(s.c_str(), &stop, 2);
return l;
}

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

422Microsoft Visual C++/CLI Step by Step

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

5. Add an mp ementat on of the ConvertOutputString funct on to the source code fi e


Platform::String^ ProgCalc::MainPage::ConvertOutputString(int val)
{
wchar_t buff[80];
if (base == Base::HEX)
swprintf(buff, 80, L"%x", val);
else if (base == Base::DEC)
swprintf(buff, 80, L"%d", val);
else if (base == Base::BIN)
{
String ^bf = ToBinary(val);
return bf;
}
return ref new String(buff);
}

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

7. Add the mp ementat on to Ma nPage xam cpp


String^ ProgCalc::ToBinary(int n)
{
String ^s = ref new String();
do {
s += (n & 1) ? L'1' : L'0';
}
while (n >>= 1);
std::wstring result(s->Data());
std::reverse( result.begin(), result.end() );
s = ref new String(result.c_str());
return s;
}

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

Chapter 21 More about W ndows Store apps 423

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;

Here s the comp ete hand er, for reference


void ProgCalc::MainPage::BaseButtons_Click(Platform::Object^ sender,
Windows::UI::Xaml::RoutedEventArgs^ e)
{
// Get the value from the display
int val = 0;
if (txtOutput->Text->Length() > 0)
val = ConvertTextToInt(txtOutput->Text);
// Get the button that was pressed
Button ^btn = (Button^)sender;

424Microsoft Visual C++/CLI Step by Step

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;
}

10. Ed t the EqualsButton Click funct on so that the output w

be converted to the r ght base


Locate the nes at the end of the funct on that use swprintf and p ace the resu t nto a buffer,
wh ch shou d ook ke th s

wchar_t buff[80];
swprintf(buff, 80, L"%d", result);
txtOutput->Text = ref new String(buff);

Rep ace them w th the fo ow ng code


txtOutput->Text = ConvertToOutputString(result);
clearOnNextKey = true;

11. Bu d and run the app, and test t thorough y!

Using app bars


The W ndows Store UI mode doesnt support menus or d a og boxes The dea s that the des gn
shou d make t easy for the user to nav gate h s way through the app by us ng the contro s on the
page rather than hav ng to pu down menus and use d a og boxes, wh ch cou d be awkward on a
touch dev ce
There are t mes, however, when users need to adjust sett ngs or express preferences For examp e,
n the weather app you m ght want to sw tch from Fahrenhe t to Ce s us, or v ce versa Hav ng these
on the ma n UI wou d c utter th ngs up, so there s a need for a way to expose these to the user, as
needed W ndows Store apps use app bars to present nav gat on, commands, and too s to users

Chapter 21 More about W ndows Store apps 425

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

Defining the button styles


The buttons on an app bar are usua y round, and th s s prov ded by a set of sty es Before add ng the
app bar to your app, you need to ed t the sty es so that they w d sp ay correct y

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

426Microsoft Visual C++/CLI Step by Step

1. Open StandardSty es xam , and search for Standard AppBarButton Styles

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>

4. Save the StandardSty es xam fi e

Adding an app bar


Now that you have set up the sty es for the three buttons, you can add the app bar
1. Add th s XAML to the bottom of the Page e ement, mmed ate y after the end of the Grid
<Page.BottomAppBar>
<AppBar x:Name="bottomAppBar" Padding="10, 0 10, 0">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<Button x:Name="btnAppBarDec" Style="{StaticResource DecAppBarButtonStyle}"
Click="BaseButtons_Click"/>
<Button x:Name="btnAppBarHex" Style="{StaticResource HexAppBarButtonStyle}"
Click="BaseButtons_Click"/>
<Button x:Name="btnAppBarBin" Style="{StaticResource BinAppBarButtonStyle}"
Click="BaseButtons_Click"/>
</StackPanel>
</AppBar>
</Page.BottomAppBar>

Chapter 21 More about W ndows Store apps 427

The BottomAppBar e ement conta ns an AppBar, wh ch n turn conta ns a StackPanel A


StackPanel s a conta ner that conta ns a stack of tems, n th s case arranged hor zonta y and
eft-a gned L ke menus, t s a convent on that commands on a bottom app bar shou d be
eft-a gned, and any buttons for he p shou d be r ght-a gned on the other s de of AppBar
Each button has the appropr ate sty e set and s nked to the base buttons c ck hand er
2. Bu d and run the app When the UI appears, r ght-c ck w th the mouse or sw pe upward from

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

screen and the app bar buttons


if (btn == btnHexBase || btn == btnAppBarHex)

2. Bu d and run the app

You can now change the base by us ng the app bar

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

Contracts and charms


App cat ons can commun cate and share data by us ng contracts W ndows Store apps use contracts
to dec are the nteract ons that they support w th other app cat ons
These contracts are defined by W ndows RT, and by us ng the W ndows operat ng system as an
ntermed ary, apps can commun cate w thout know ng anyth ng about one another
For examp e, choos ng the Share charm wh e n an app w d sp ay a app cat ons that have regstered themse ves as targets for shar ng Th s means that you can send data from your app to any of
the shar ng targets w thout the two part es hav ng pr or know edge of one another
W ndows 8 defines the fo ow ng s x contracts

Search The app s search enab ed

428Microsoft Visual C++/CLI Step by Step

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

Settings Imp ements a standard way of defin ng app sett ngs

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

Share content from your app w th peop e or serv ces

Go d rect y to the Start screen

Connect to dev ces and send content, stream med a, and pr nt

Configure the 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

Deve oper-defined data

Chapter 21 More about W ndows Store apps 429

5. Set up the DataTransferManager so that shar ng s act ve for the app Start by add ng a new

pr vate member to the MainPage c ass, as shown here


Windows::Foundation::EventRegistrationToken dataRequestedToken;

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

before the ca to Reset


DataTransferManager ^dataTransferManager = DataTransferManager::GetForCurrentView();
dataRequestedToken = dataTransferManager->DataRequested +=
ref new TypedEventHandler<DataTransferManager^,
DataRequestedEventArgs^>(this, &MainPage::ShareTextHandler);

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

the second from the top


After a few seconds n t a zat on, you shou d see the t t e and descr pt on you prov ded, together w th a st of the app cat ons that can accept the data, as demonstrated n th s screen
shot

432Microsoft Visual C++/CLI Step by Step

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

Add an app bar to ho d command buttons

F rst create sty es for the buttons n StandardSty es.


xam . Add a BottomAppBar to the XAML. Then, add a
StackPanel conta n ng the buttons, and nk the r click
events to a su tab e hand er.

mp ement the shar ng contract.

Add a hand er for a DataRequestedEvent and put the data


nto a DataPackage. Then, use the DataTransferManager
to make shar ng ava ab e for that page.

Chapter 21 More about W ndows Store apps 433

PAR T IV

Advanced topics
CHAPTER 22

Work ng w th unmanaged code

437

CHAPTER 23

Attr butes and reflect on

453

CHAPTER 24

L v ng w th COM

475


435

CHAPTER 22

Working with unmanaged code


After comp et ng th s chapter, you w

be ab e to

Exp a n the ssues that affect managed and unmanaged code

Use managed objects n unmanaged code

Use the P atform Invoke mechan sm to ca unmanaged funct ons n DLLs

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

he System::Runtime::InteropServices namespace conta ns c asses and structures to he p w th


nteroperat on between NET and the outs de wor d In th s chapter, I ntroduce one feature of
the namespacethe P atform Invoke mechan sm for ca ng unmanaged funct ons w th n DLLs We
a so nvest gate some of the other ssues that surround nteract ng w th unmanaged code Chapter 24,
L v ng w th COM, cons ders cons ders nteroperat ng between the Component Object Mode (COM)
and NET

Managed vs. unmanaged code


Code and data that ve n the NET wor d are ca ed managed because ocat ons and fet mes are
managed by the Common Language Runt me (CLR) Code and data that ex st outs de of NET are
ca ed unmanaged, because there s no centra mechan sm for manag ng the r fet mes Somet mes
you have to m x the two, ca ng ex st ng unmanaged code from w th n NET Th s sect on ntroduces
some of the ssues and techn ques that you need to cons der n th s s tuat on

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

// C4368: mixed types are not supported

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;

// C3265: cannot declare a managed 'obj'


// in an unmanaged 'UnmanagedClass'

...
};

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

The GCHandle type


There s a way to use a managed type as part of an unmanaged c ass by us ng the GCHandle type
prov ded n the System::Runtime::InteropServices namespace GCHandle asks the runt me to g ve you
a hand e to refer to a managed object from unmanaged code You use the GCHandle::Alloc stat c
method to create the hand e, and the hand es Free method to re ease t aga n Heres how youd use
GCHandle f you wanted to pass a po nter to a managed object to unmanaged code
1. Create a GCHandle to refer to your object GCHandles can be converted to and from ntegers

for ease of pass ng them between funct ons

438Microsoft Visual C++/CLI Step by Step

2. Pass the GCHandle to the unmanaged code As ong as the hand e hasnt been freed, the

runt me wont co ect the object


3. Ca Free on the hand e when the unmanaged code no onger needs t At th s po nt, the run-

t me s free to co ect the object f no one e se s us ng t


To he p you use GCHandles w th n unmanaged code w thout your hav ng to get nto the deta s of
us ng Alloc and Free, M crosoft prov des a he per temp ate c ass ca ed gcroot The fo ow ng exerc se
shows you how to use gcroot to nc ude a po nter to a managed type as part of an unmanaged c ass
1. Start M crosoft V sua Stud o 2012 and create a new CLR Conso e App cat on project named

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>

Th s system header fi e defines the gcroot he per c ass


3. Add a using d rect ve to the top of the code to make t eas er to use the System::Runtime::Interop

Services namespace
using namespace System::Runtime::InteropServices;

4. Add the defin t on of a s mp e managed c ass to the code


ref class MClass
{
public:
int val;
MClass(int n) : val(n) { }
};

Th s c ass s mp y wraps an nteger, whose va ue s set n the constructor


5. Add the defin t on of an unmanaged c ass
class UClass
{
public:
gcroot<MClass^> mc;
UClass(gcroot<MClass^> pmc) : mc(pmc) { }
int getValue()
{
return mc->val;
}
};

Chapter 22 Work ng w th unmanaged code 439

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.

7. Bu d and run the app cat on

Pinning and boxing


Th s sect on d scusses two C++/CLI concepts, pinning and boxing, and shows you how theyre used n
code

440Microsoft Visual C++/CLI Step by Step

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;
}

Chapter 22 Work ng w th unmanaged code 441

Here s how we cou d use th s w th a managed array


// Create a managed array of int
array<int> ^arr = gcnew array<int>(5);
// Create a pinning pointer to the first element
// Note there is no '^', and that '&' is used to take the address of the object
pin_ptr<MyClass> pin = &arr[0];
// Pass the integer member to an unmanaged function
someFunc(pin);
// Zero out the pinning pointer
// The array is not pinned any more
pin = nullptr;

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

Boxing and unboxing


Boxing and unboxing, wh ch w be d scussed n a moment, make t poss b e for va ue types to be
treated as objects Chapter 9, Va ue types, covers va ue types n deta and teaches that they are
fundamenta y d fferent from reference types To recap, va ue types have three part cu ar propert es

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

442Microsoft Visual C++/CLI Step by Step

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

A managed object s created on the CLR heap

The va ue of the va ue type s cop ed, b t by b t, nto the managed object

The address of the managed object s returned

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;
}

Chapter 22 Work ng w th unmanaged code 443

3. Add the fo ow ng code to get the va ue back out of the box


// Unbox the value
int fooTwo = safe_cast<int>(obj);
Console::WriteLine("fooTwo is {0}", fooTwo);

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

Using P/Invoke to call functions in the Win32 API


A though ts poss b e to do a great dea by us ng the funct ona ty prov ded n the NET Framework,
at t mes you need to use code that wasnt wr tten for NET to accommodate s tuat ons such as the
fo ow ng

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

444Microsoft Visual C++/CLI Step by Step

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

Chapter 22 Work ng w th unmanaged code 445

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

446Microsoft Visual C++/CLI Step by Step

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

Automat c ayout (LayoutKind::Auto), n wh ch the runt me m ght reorder the members f t s


more effic ent You never use automat c ayout for types that are go ng to be used w th
P/Invoke because you need to be sure that everyth ng stays n the same order
Exp c t ayout (LayoutKind::Explicit), n wh ch members are ordered accord ng to byte offsets
spec fied by FieldOffset attr butes on each fie d
Sequent a ayout (LayoutKind::Sequential), n wh ch members appear n unmanaged memory
n the same order they appear n the managed defin t on

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;

The prototype for the GetSystemPowerStatus funct on n the API documentat on s th s


BOOL GetSystemPowerStatus(
LPSYSTEM_POWER_STATUS lpSystemPowerStatus
);

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

Th s makes t eas er to refer to the attr butes we be us ng ater

Chapter 22 Work ng w th unmanaged code 449

3. Define a managed equ va ent for the structure


[StructLayoutAttribute(LayoutKind::Sequential)]
ref class PStat {
public:
System::Byte ACLineStatus;
System::Byte BatteryFlag;
System::Byte BatteryLifePercent;
System::Byte Reserved1;
System::UInt32 BatteryLifeTime;
System::UInt32 BatteryFullLifeTime;
};

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

to ca the funct on, as

ustrated n the fo ow ng

int main(array<String^>^ args)


{
Console::WriteLine("Power Status Test...");
PStat ^ps = gcnew PStat();
BOOL b = GetSystemPowerStatus(ps);
Console::WriteLine("Got status, return was {0}", b);
return 0;
}

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

450Microsoft Visual C++/CLI Step by Step

// Report on the AC line status


Console::Write("AC line power status is ");
switch(ps->ACLineStatus) {
case 0:
Console::WriteLine("'off'");
break;
case 1:
Console::WriteLine("'on'");
break;
case 255:
Console::WriteLine("'unknown'");
break;
}
// Report on the battery status
Console::Write("Battery charge status is ({0})",
ps->BatteryFlag);
if (ps->BatteryFlag & 1)
Console::Write(" 'high'");
if (ps->BatteryFlag & 2)
Console::Write(" 'low'");
if (ps->BatteryFlag & 4)
Console::Write(" 'critical'");
if (ps->BatteryFlag & 8)
Console::Write(" 'charging'");
if (ps->BatteryFlag & 128)
Console::Write(" 'no system battery'");
Console::WriteLine();
// What's the percentage charge left in the battery?
// A value of 255 means unknown
if (ps->BatteryLifePercent == 255)
Console::WriteLine("Battery life unknown");
else
Console::WriteLine("Battery life is {0}%",
ps->BatteryLifePercent);
// How many seconds battery life is left?
if (ps->BatteryLifeTime == -1)
Console::WriteLine("Battery life in seconds: Unknown");
else
Console::WriteLine("Battery seconds remaining: {0} secs",
ps->BatteryLifeTime);

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

obv ous y ach eve the best resu ts f you run t on a

aptop

Chapter 22 Work ng w th unmanaged code 451

Quick reference
To

Do this

Obta n a safe hand e to a managed object so that


t won t be garbage co ected wh e be ng used.

Use the System::Runtime::InteropServices::GCHandle::Alloc func


t on to wrap a po nter to a managed object n a GCHandle.
The eas est way to do th s s to use the gcroot he per c ass. For
examp e:
Foo ^ff = gcnew Foo();
gcroot<Foo^> pf = ff;

Th s code wraps the po nter to the Foo object w th a GCHandle,


and hand es c eanup when the gcroot s destroyed.
F x a or part of a managed object n memory so
that t can be used safe y by unmanaged code.

Use pin ptr<> to create a p nn ng po nter. For examp e:


pin_ptr<Foo> p = gcnew Foo();

The managed Foo object won t be moved n memory or garbage


co ected unt the p nn ng po nter goes out of context or has nu
ass gned to t.
Convert a va ue type to an object so that t can be
used where an object s requ red.

Th s w happen automat ca y. Note that the va ue n the box s a


copy of the or g na .

Retr eve the va ue from a boxed object.

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

Ca an unmanaged funct on n a DLL.

452Microsoft Visual C++/CLI Step by Step

Use the P/ nvoke mechan sm by dec ar ng a prototype for the un


managed funct on that uses the DllImport attr bute to spec fy the
DLL n wh ch the funct on res des and other opt ona parameters.

CHAPTER 23

Attributes and reflection


After comp et ng th s chapter, you w

be ab e to

Descr be what attr butes are

Use attr butes to add metadata to managed types

Create your own attr bute types

Access attr bute metadata from code

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

Metadata and attributes


The concept of metadata s centra to the way the M crosoft NET Framework works, so to be an
effect ve NET programmer, you need to know what t s and how to work w th t Metadata s data
attached to NET data types that carr es nformat on about those types ( n a broader sense, t s
datathat descr bes data) A ot of metadata conta ns nformat on that cant be spec fied n the programm ng anguage, and t offers a usefu many peop e wou d say essent a way to prov de a the
extra nformat on needed by the NET runt me
One of the major advantages of metadata s that t s stored a ong w th the code, so extra data
doesnt need to be stored separate y Trad t ona y, n W ndows a extra data has to be stored n the
W ndows reg stry One of the ma n prob ems w th th s s ensur ng that the data n the reg stry doesnt
become corrupt or out of step w th the code
Another major advantage of metadata s that t prov des a way to add vers on nformat on to the
code so that you know wh ch vers on of a component youre us ng Th s so ves a ot of prob ems that
have p agued programmers s nce the ear y days of W ndows; t s a huge step forward


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

type ildasm on the command ne


5. On the ILDASM F e menu, c ck Open, nav gate to the He o exe executab e, and then open t

454Microsoft Visual C++/CLI Step by Step

A w ndow opens that shou d ook s m ar to the fo ow ng

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

Chapter 23 Attr butes and reflect on 455

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

A w ndow s m ar to the fo ow ng appears

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

456Microsoft Visual C++/CLI Step by Step

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

Using predefined attributes


In th s sect on, you earn how to use the attr butes that are predefined by the NET Framework You
can use these attr butes n two ways by ed t ng the Assemb yInfo cpp fi e that comes as part of a C++/
CLI project, and by attach ng attr butes to managed e ements n your code

The AssemblyInfo.cpp file


Every C++/CLI project nc udes an Assemb yInfo cpp fi e that conta ns code affect ng the attr butes
app ed to the assemb y You can ed t th s fi e to custom ze the assemb y attr butes, wh ch w be used
to set the metadata n the assemb y at bu d t me The fo ow ng exerc se shows you how to mod fy
assemb y attr butes
1. Create a new CLR Conso e App cat on project named AssemblyAttributes
2. Open the Assemb yInfo cpp fi e and exam ne ts contents

Observe that the fi e conta ns a number of entr es of the fo ow ng form


[assembly:AssemblyTitleAttribute("AssemblyAttributes")];

Many of these have empty str ngs as arguments


3. F nd the vers on number attr bute and ed t t to produce a new vers on, such as n the fo ow-

ng examp e
[assembly:AssemblyVersionAttribute("1.1.105.3")];

Th s number wou d correspond to vers on 1 1, bu d 105, rev s on 3


4. Comp e and bu d the app cat on If you now ook at the assemb y by us ng ILDASM, you can

see the vers on n two p aces F rst, t w


w ndow, as demonstrated here

show n the pane at the bottom of the ILDASM ma n

Chapter 23 Attr butes and reflect on 457

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

You add code to th s project ater on n the exerc se

Chapter 23 Attr butes and reflect on 459

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,

so you mark t as obso ete by us ng the Obsolete attr bute


[Obsolete("Use the Val property instead", false)]
int getVal() { return val; }

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

460Microsoft Visual C++/CLI Step by Step

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;

10. Ed t the main funct on to create an object and ca

ts obso ete get method, as shown here

int main(array<System::String ^> ^args)


{
TestClass ^tc = gcnew TestClass(4);
int n = tc->getVal();
return 0;
}

11. Bu d the app cat on

You shou d see the fo ow ng warn ng from the comp er


UseAttributes.cpp(12): warning C4947: 'MyDll::TestClass::getVal' : marked as obsolete
Message: 'Use the Val property instead'

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.

Defining your own attributes


As you see n th s sect on, you can eas y define custom attr butes and use them n your projects
Custom attr butes are qu te s mp e to wr te because an attr butes parameters are s mp y represented
by a c ass w th propert es and methods For examp e, suppose you had the fo ow ng attr bute attached to a c ass des gned to contro the generat on of ogg ng nformat on at run t me
[LogAttribute("myfile.log", type=LogAttribute::AllMethods)]
ref class MyClass...

Chapter 23 Attr butes and reflect on 461

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

Attribute class properties


A though some attr butes have no parameters, most w
nto two groups

spec fy at east one Attr bute parameters fa

Positional parameters, wh ch are dent fied s mp y by the r pos t on n the parameter st

Named parameters, wh ch are spec fied as a name/va ue pa r

Cons der the custom attr bute we used as an examp e


[LogAttribute("myfile.log", type=LogAttribute::AllMethods)]

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

Design criteria for attribute classes


Before mov ng on to the exerc se, here are a few des gn cr ter a that you shou d keep n m nd when
you wr te a custom 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)

Use pos t ona arguments for requ red parameters

Use named arguments for opt ona parameters

Prov de a read-on y property for each pos t ona argument

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)

Writing a custom attribute


Th s exerc se shows you how to create a custom attr bute that can be used to document methods and
propert es In the next sect on, you see how to wr te code that makes use of th s attr bute
1. Create a new CLR C ass L brary project named CustomAttributes

The custom attr bute needs to be created as a DLL so that t can be used n other projects

Chapter 23 Attr butes and reflect on 463

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
};
}

4. Add the constructor


public:
DocumentationAttribute(String ^txt) : text(txt) { }

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; }
}

464Microsoft Visual C++/CLI Step by Step

6. Add read/wr te propert es to a ow access to the two named parameters


// Properties for the positional parameters
property String^ Author
{
String^ get() { return author; }
void set(String ^au) { author = au; }
}
property String^ Date
{
String^ get() { return date; }
void set(String ^dt) { date = dt; }
}

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

use the new attr bute 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 se ect New Project Ensure
that the project type s set to CLR Conso e App cat on and ca the project TestAtts

9. Add an externa reference to the CustomAttr butes DLL, just as you d d n steps 7 and 8 of the

prev ous exerc se


10. Open the TestAtts cpp fi e and add a using namespace ne to the top of the fi e
using namespace CustomAttributes;

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; }
}
};

Chapter 23 Attr butes and reflect on 465

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-

c ck the .ctor entry


Th s opens the d sassemb y for the constructor, as shown here

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
{
...
}

466Microsoft Visual C++/CLI Step by Step

When you comp e th s code, the comp er w


attr bute cannot be app ed to c asses

throw the fo ow ng error message because the

TestAtts.cpp(8): error C3115: 'CustomAttribute::DocumentationAttribute': this attribute


is not allowed on 'TestAtts'
c:\users\julian\documents\sbs\customattribute\debug\customattribute.dll : see
declaration of 'CustomAttribute::DocumentationAttribute'
attribute can only be applied to: 'member function', 'property'

Using reflection to obtain attribute data


The fina sect on of th s chapter shows you how to use attr butes at run t me by nqu r ng about what
attr bute data an object conta ns

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

The Type class


Before I ta k about reflect on and how t re ates to attr butes, you need to know someth ng about
the Type c ass System::Type s a c ass that represents type dec arat ons Th s means that you can get a
Type object to represent any object or type to wh ch you have a reference, and you can then use that
object to find out many deta s about the type You can obta n Type objects to represent va ue types,
arrays, c asses, nterfaces, and enumerat ons It s the pr mary way to access metadata and the way n
wh ch you use reflect on A though the Type c ass s used ma n y by deve opers wr t ng anguage too s,
you m ght find t usefu at t mes, such as when you want to access c ass attr butes

Chapter 23 Attr butes and reflect on 467

Accessing custom attribute data


Custom attr bute data s accessed by us ng the stat c GetCustomAttribute and GetCustomAttributes
members of the Attribute c ass As youd expect, GetCustomAttribute retr eves nformat on about
one attr bute, whereas GetCustomAttributes returns you an array conta n ng deta s of a the custom
attr butes for a type Th s exerc se shows you how to use the Type c ass and the GetCustomAttributes
method to retr eve the attr bute sett ngs from the c ass you created n the prev ous exerc se
1. Cont nue w th the project from the prev ous exerc se
2. A c asses dea ng w th reflect on res de n the System::Reflection namespace, so add the fo -

ow ng using dec arat on to the others at the top of the source


using namespace System::Reflection;

3. You need to create a Type object to use reflect on to find out about custom attr butes, so add

th s code to the start of the main funct on


int main(array<String^>^ args)
{
Console::WriteLine("Testing Attributes");
// Create an object and get its type
TestAtts ^ta = gcnew TestAtts(3);
Type ^tt = ta->GetType();
return 0;
}

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

Attributes method on the Type object, ke th s


// See if there are any custom attributes on the class
array<Object^> ^atts = tt->GetCustomAttributes(true);
Console::WriteLine("Custom attributes on the class: {0}",
atts->Length);

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

need to set t as the startup project In So ut on


Exp orer, r ght-c ck the project name, and then, on the shortcut menu, c ck Set As Startup
Project
The project name shou d now be d sp ayed n bo d Th s w be the project that s started
when you nstruct V sua Stud o to run the projects n the so ut on

470Microsoft Visual C++/CLI Step by Step

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

c ass members and query them, as shown n the fo ow ng


// Get info on the class members
array<MemberInfo^> ^mi = tt->GetMembers();
Console::WriteLine("Class members: {0}", mi->Length);

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

Chapter 23 Attr butes and reflect on 471

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

Mod fy the assemb y eve attr butes n a c ass.

Ed t the entr es n the Assemb y nfo.cpp fi e that s gener


ated for a C++/CL projects n V sua Stud o 2012.

F nd out about the standard attr butes of a type.

Use the Attributes property on a Type object that repre


sents the type, and use the b tw se AND operator (&) to
compare the va ue w th members of the TypeAttributes
enumerat on. For examp e:
if ((t->Attributes & TypeAttributes::Public) ==
TypeAttributes::Public)

Create a custom attr bute.

Create a c ass to represent an attr bute, and use the


AttributeUsage attr bute to contro where your attr bute
can be app ed. For examp e:
[AttributeUsage(AttributeTargets::Method)] public
ref class MyAttribute { ... };

Represent mandatory parameters for a custom attr bute.

Add arguments to the c ass constructor or constructors


p us read on y propert es to g ve access to the va ues.

Represent opt ona parameters for a custom attr bute.

Add a property to represent each opt ona parameter.

472Microsoft Visual C++/CLI Step by Step

CHAPTER 24

Living with COM


After comp et ng th s chapter, you w

be ab e to

Descr be how you can use Component Object Mode (COM) objects from NET projects

Use COM objects through ear y and ate b nd ng

Use Act veX contro s n W ndows Forms projects

Expose NET objects as COM objects

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

COM components and the COM Interop


The des gners of the NET Framework recogn zed that even though the framework s eas er to use and
more flex b e than COM for many app cat ons, t doesnt tota y rep ace COM For th s reason, they
deve oped the COM Interop fac ty so that NET and COM objects can nteract
As you see short y, t s easy to use a COM object from NET code, and th s g ves NET deve opers
access to hundreds of ex st ng COM objects It s a so poss b e to use a NET object from COM code,
a though Id expect th s to be a ess common occurrence

Using COM components from .NET code


To use a COM object from NET code, you first create a Runtime Callable Wrapper (RCW) You need
the RCW because of severa major d fferences between COM and NET, wh ch are summar zed n the
fo ow ng tab e
COM

.NET

C ents must manage the fet mes of the COM objects


they create.

The Common Language Runt me (CLR) manages the fe


t me of .NET objects.

C ents use QueryInterface or browse the object s type


nformat on to find out whether a part cu ar nterface s
supported.

C ents can use reflect on to query an object.

COM objects are accessed through raw po nters and are


therefore fixed n memory.

.NET objects are accessed through references and can be


moved around by the CLR for performance reasons.

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

How do RCWs work?


The wrapper takes the form of a proxy c ass that does a the work of creat ng and ta k ng to the COM
object, so you can use COM objects just as f they were NET objects You can see how th s works n
the d agram that fo ows The RCW does a the housekeep ng by nteract ng w th the W ndows Regstry, creat ng the object, forward ng ca s to the object, and manag ng ts fet me The pr mary goa
of the RCW s to h de the comp ex ty of COM objects from NET programmers; n some cases, NET
programmers m ght not even know they are us ng a COM object

476Microsoft Visual C++/CLI Step by Step

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

entry to add a check mark and then c ck OK

5. You w

see that a new entry for TempConverterLib has been added to the projects st of
references

478Microsoft Visual C++/CLI Step by Step

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

COM co-c ass and append C ass


Chapter 24 L v ng w th COM 479

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

Handling COM errors


You know that COM methods return status and error nformat on by us ng 32-b t HRESULTs The
RCW converts a error HRESULTs nto except ons that you can catch n your code The test Converter
project returns an error f the convers on methods are passed any va ues ess than 273C or 459F
because temperatures ess than abso ute zero have no mean ng Heres the COM code
STDMETHODIMP CConverter::ConvertC2F(double dCelsius, double* dFahr)
{
if (dFahr == 0) return E_POINTER;
// Temperatures below -273C are meaningless...
if (dCelsius < -273.0) return E_INVALIDARG;
*dFahr = (9/5.0 * dCelsius) + 32;
return S_OK;
}

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

Late binding to COM objects


RCWs mp ement ear y b nd ng connect ons to COM objects, because when you have a type brary,
you have a the deta s of what the COM object can do ava ab e to you at comp e t me If you want
to use a COM object that mp ements IDispatch, you can a so ca t at run t me, but the process s a
tt e more comp ex
The exerc se that fo ows shows how to use the TempConverter object w th ate b nd ng Th s COM
object was created w th a dua nterface, so t can be accessed v a both ear y b nd ng and ate b nd ng
1. Create a new CLR Conso e App cat on project named LateBind
2. Add code to main to get a Type object that represents the COM component (Consu t Chap-

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

Chapter 24 L v ng w th COM 481

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

form of an array of Objects, as shown here


// Make up the argument list
array<Object^> ^argarray = { 27.0 };

Here, the array conta ns on y one va ue the temperature to be converted


5. Ca the convers on method dynam ca y, us ng the InvokeMember method of the Type c ass
// Invoke the method
try
{
Object ^result = t->InvokeMember("ConvertC2F",
Reflection::BindingFlags::InvokeMethod, nullptr, obj, argarray);
double d = Convert::ToDouble(result);
Console::WriteLine("27C is {0}F", d);
}
catch(Exception ^ex)
{
Console::WriteLine("Exception from Invoke: ", ex->Message);
}

InvokeMember, as ts name mp es, dynam ca y nvokes a member of an object The arguments


supp ed to the funct on are the name of the member to be nvoked, the type of operat on ( n
th s case, youre nvok ng a method rather than access ng a property or fie d), a hand e to a
Binder object (wh ch youre not us ng), a hand e to the object on wh ch the operat on s to be
nvoked, and a hand e to the argument array
If the ca works, you be passed back an Object reference represent ng the resu t, wh ch s
then converted to the appropr ate type by us ng one of the stat c methods of the Convert
c ass
6. Bu d and run the app cat on, and check that you get the r ght answer (wh ch s 80 6F)

482Microsoft Visual C++/CLI Step by Step

Using .NET components as COM components


In add t on to us ng COM objects from NET c ents, you can use NET objects n the COM wor d The
process for expos ng NET c asses as COM objects s comp ex because nteract ng w th COM at the
C++ eve s d fficu t For th s reason, th s sect on ntroduces the top c but eaves the pract ca mp ementat on of NET-to-COM code for more advanced texts
Aga n, wrapper c asses are used, on y th s t me they are ca ed COM Ca ab e Wrappers (CCWs) In
effect, a CCW puts a COM ayer onto a NET object so that the NET object behaves n exact y the way
a COM object s expected to behave The process s shown here

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

What must .NET types implement to be used as COM objects?


COM objects have a part cu ar set of character st cs, and NET types need to fo ow some ru es f
theyre to be exposed as COM objects us ng COM Interop Heres a summary of what the NET type
must to do

It must supp y a defau t constructorone that doesnt take argumentsbecause COM


objects are a ways created un n t a zed, and theres no standard way to pass over n t a zat on
data For th s reason, t must be poss b e to create NET objects un n t a zed f theyre to be
used as COM objects
The types assemb y must be s gned w th a strong name See the upcom ng s debar Names
and s gn ng for deta s on strong names and how to use them
The types assemb y must be p aced where the CLR can find t See the upcom ng s debar
Insta ng assemb es for more deta s
The correct COM-re ated reg stry entr es must be made for the NET object Th s s done for
you automat ca y f youre us ng V sua Stud o

Chapter 24 L v ng w th COM 483

Names and signing


Assemb es are norma y dent fied by the r name, vers on number, and poss b y oca e nformat on Th s s adequate for pr vate assemb es that w be used on y w th n a s ng e app cat on
However, t snt good enough for those that w be used more w de y because two peop e
cou d use the same name for the r assemb es, resu t ng n ots of potent a for confus on
To make assemb es un que, they shou d be g ven a strong name, wh ch cons sts of the
text name, vers on, and oca e nformat on, p us a pub c key and a d g ta s gnature Every key
generated by us ng Pub c Key Encrypt on s un que, so us ng keys and d g ta s gnatures serves
both to prov de a un que dent fier for an assemb y, and a way to ver fy the assemb y owner or
creator
COM requ res that components be un que y dent fied, and t uses GUIDs to accomp sh th s
NET strong names fu fi the requ rement for un que component dent ficat on, and they a so
prov de nformat on about the components or g nator, wh ch GUIDs do not

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

484Microsoft Visual C++/CLI Step by Step

Quick reference

To

Do this

Use a COM object from .NET code.

f you re us ng V sua Stud o 2012, use the Propert es


d a og box to add a reference to the COM component. f
you re comp ng from the command ne, use the t b mp.
exe too to generate an RCW for the COM object, and
then reference the wrapper n your code as you wou d
any other .NET c ass.

Use a COM object v a ate b nd ng.

Use the stat c GetTypeFromProgID or GetTypeFromCLSID


methods of the Type c ass to generate a Type object rep
resent ng the COM object. Then, use the CreateInstance
stat c method on the System::Activator c ass to create an
nstance of the object. F na y, use InvokeMember on the
Type object to nvoke your chosen member.

Use a .NET component n a COM project.

Create a CCW.

Chapter 24 L v ng w th COM 485

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

<> syntax, 207


%x descr ptor, 422

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

copy ng e ements, 215


overv ew, 212
search ng, 216 217
sort ng, 217 218
us ng enumerators w th, 218 219
Array::Sort method, 217
AsReadOn y method, 212
assemb es
ADO.NET, 336
.NET, 266
Assemb yCompanyAttr bute, 267, 268
Assemb y nfo.cpp fi e
predefined attr butes, 457 458
assemb y nker, 6
assemb y man fest, 266
Assemb y property, 468
Assemb yQua fiedName property, 468
Assets fo der, 379
ass gn ng var ab es, 26 27
ass gnment convers ons, 26
ass gnment operator (=), 26, 30
aster sk (*) symbo , 438
attached propert es, 386 387
Attr buteCount property, 307, 315
Attr bute node type, 309
attr butes
and metadata
overv ew, 453 454
us ng LDASM, 454 457
defin ng custom
creat ng, 463 467
des gn cr ter a for attr bute c asses, 463 464
overv ew, 461 463
propert es for, 463 464
predefined attr butes
Assemb y nfo.cpp fi e, 457 458
c asses for, 458 461
overv ew, 457
us ng reflect on to obta n
access ng custom attr bute data, 470 472
access ng standard attr butes, 469
overv ew, 467 468
Type c ass, 467 469
Attr butes property, 291, 323, 326, 468
Attr buteTargets enumerat on, 464
Attr buteUsage attr bute, 462, 464
Attr buteUsageAttr bute c ass, 458, 462
AutoC ass attr bute, 469
auto gcroot type, 440
auto mp emented propert es, 233

CCWs (COM Callable Wrappers)


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

Button contro , 383


Button e ement, 376
Byte type, 271
Byte va ue type, 144

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

CDATA node type


CDATA node type, 309
charms
n ca cu ator examp e, 428 429
n W ndows Store apps, 374
CharSet fie d, 447, 448
Char type, 24, 271
Char va ue type, 145
CheckBox contro , 384
CheckCharacters property, 310
Check ngAccount c ass, 15
Ch dNodes property, 323, 326
C rc e c ass, 236
C ass attr bute, 469
c asses
abstract c asses, 130 131
base c asses, 126 129
c ass w de members
data members, 88 89
member funct ons, 90 91
overv ew, 87 88
stat c constructors, 92 93
concrete c asses, 130 131
constants n
c ass w de constants, 93 94
nstance constants, 94 95
overv ew, 93
constructors
defin ng, 84 86
member n t a zat on sts, 86 87
creat ng objects, 83 84
for custom attr butes, 463 464
der ved c asses, 129 130
and fina zers, 106
n header fi es, 79 80
n source fi es, 81 82
n object or ented programm ng, 16
object re at onsh ps
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
organ z ng, 78 79
overr d ng member funct ons, 131 136
for predefined attr butes, 458 461
protected access, 136 137
sea ed c asses
and abstract c asses, 137
overv ew, 137

490Index

vs. structures, 149 150


n W ndows RT, 391 392
c ass keyword, 20
c ass brary, .NET, 265
c ass members, 77
c ass w de constants, 93 94
c ass w de members
data members, 88 89
member funct ons, 90 91
overv ew, 87 88
stat c constructors, 92 93
C earButton C ck method, 402
C ear method, 212
c earOnNextKey var ab e, 409
C one method, 212, 324, 326
C oneNode method, 324, 326
C ose method, 283, 287, 298, 299, 308, 318
CLR (Common Language Runt me), 20, 263 264,
336, 437, 454
CLS (Common Language Spec ficat on), 160, 265,
298
CLSComp antAttr bute c ass, 458
CLS comp ant operators, over oad ng, 166 167
code beh nd fi es, 379, 382
code reuse, and nher tance, 122
co ect ons
L st<T> c ass, overv ew, 219 221
overv ew, 219
SortedL st<K,V> c ass, overv ew, 222 223
Co ect ons nterfaces, 273 274
Co ect ons namespaces, 272 273
Co umnDefin t on e ement, 386
Co umn property, 387
Comb ne method, 250
ComboBox contro , 384
COM Ca ab e Wrappers (CCWs), 483
COM (Component Object Mode ), 276
overv ew, 475 476
us ng from .NET code
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
CommandText property, 340
Comment node type, 309

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

convers on operator, 164


ConverterC ass, 479
convert ng constructors, 164
ConvertOutputStr ng funct on, 423
ConvertTextTo nt funct on, 407, 421
Convert::To nt32 funct on, 44
copy constructors, overv ew, 113 116
Copy method, 212, 215, 292
CopyTo method, 212, 293
Count property, 220
count var ab e, 289
CreateAttr bute method, 324
CreateCDataSect on method, 324
CreateComment method, 324
CreateDefau tAttr bute method, 324
CreateD rectory method, 290
CreateDocumentType method, 324
CreateE ement method, 324
CreateEnt tyReference method, 324
Create method, 291 293, 306, 308
CreateNav gator method, 324, 326
CreateNode method, 324
CreateProcess ng nstruct on method, 324
CreateSubd rectory method, 291
CreateText method, 292, 293
CreateTextNode method, 324
CreateWh tespace method, 324
CreateXm Dec arat on method, 324
Creat onT me property, 291, 293
Cred tCardAccount c ass, 78
CTS (Common Type System), 264
Cube funct on, 249
CurrentAccount c ass, 123, 126 127, 129 130
CurrentAccount.cpp project, 128
CurrentAccount header fi e, 129
Current property, 210, 218
custom attr butes
creat ng, 463 467
des gn cr ter a for attr bute c asses, 463 464
obta n ng data us ng reflect on, 470 472
overv ew, 461 463
propert es for, 463 464

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

ExactSpe ng fie d, 448


except ons
and safe cast keyword, 191 192
creat ng, 189 191
Except on c ass propert es, 182 183
hand ng
catch b ock, 189
Except on c ass propert es, 182 183
except on h erarchy, 184
fina y b ock, 188
try/catch b ocks, 180 182
w th constructors, 184 185
n m xed anguage programm ng, 192 195
nest ng, 185 188
overv ew, 175 178
rethrow ng, 185 188
throw ng, 178 180
types of, 178
executab e programs
comp ng source fi es, 6, 9 10
creat ng project, 8 9
runn ng program, 7, 11
source fi es for, 9
ExecuteNonQuery method, 337, 341
ExecuteReader method, 337, 342
ExecuteSca ar method, 337, 340
Ex sts method, 212, 288, 290, 292
Ex sts property, 291, 293
exp c t ayout, 449
eXtens b e Markup Language. SeeXML
Extens b e Sty esheet Language Transformat ons
(XSLT), 306
Extens b e Sty esheet Language (XSL), 276
Extens on property, 291

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

FromB nary funct on, 422


Fu Name property, 291, 293, 468
fu y qua fied name, 269
func funct on, 180
funct on header, 41
Funct on keyword, 38
funct ons
ca ng, 45 47
funct on bod es
defin ng, 41 42
overv ew, 41
parameters n, 42 43
return type, 43 45
funct on prototypes
dec ar ng, 38 39
defau t va ues for, 40
defined, 38
parameters n, 39
return type, 39 40
g oba scope, 51 53
oca scope, 51 53
non stat c member funct ons, ca ng by us ng
de egates, 249
over oad ng, 53 55
overr d ng, 131 136
pass ng arrays to, 200 202
stat c member funct ons, ca ng by us ng
de egates, 248 249

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

IDE (integrated development environment)


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

getVa funct on, 162, 164


getVa ue funct on, 440
GetVa ue method, 213
GetYear funct on, 58
G oba Assemb y Cache (GAC), 484
g oba scope, overv ew, 51 53
g oba var ab es, 52
green and b ue stacks, 372 373
Gr d contro , 375 376
Gr dV ew contro , 384

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

des gn ng h erarchy for, 123 124


nterfaces, 138 139
n object or ented programm ng, 15
overr d ng member funct ons, 131 136
overv ew, 121 122
propert es and, 235
protected access, 136 137
sea ed c asses
and abstract c asses, 137
overv ew, 137
subst tutab ty, 123 124
term no ogy, 122
n t a zeComponent method, 406
n t a ze method, 213
n ne funct ons, 19
nnerText property, 323, 326
nnerXm property, 323, 326
nput/output. See /O
nput var ab e, 44
nsertAfter method, 324, 326
nsertBefore method, 324, 326
nsertCommand, 345
nsert funct on, 221
nstance constants, 94 95
nstance members, 77
nt16 type, 271
nt16 va ue type, 144
nt32 type, 271
nt64 type, 271
nt64 va ue type, 144
ntegrated deve opment env ronment ( DE), 11
nterface attr bute, 469
nterfaces, propert es n, 235
nter or po nters, 441
ntermed ate Language ( L), 375
nter process commun cat on ( PC), 353
ntPtr type, 271
ntPtr va ue type, 145
ntPtr::Zero argument, 447
ntrospect on, 467
nt type, 18, 24
ntVa c ass, 161, 163
nva dCastExcept on, 191
nva dOperat onExcept on, 219
nvocat on st, 250
nvokeMember method, 469, 482
nvoke method, 248
OExcept on c ass, 274, 282


/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

LoyaltyScheme class example


Last ndexOf method, 213, 216
ast n, first out (L FO), 226
LastWr teT me property, 291, 293
ate b nd ng, to COM objects, 481 482
ayout
n ca cu ator examp e, 398 401
n XAML, 384 388
eft sh ft operator (<<), 32
Length property, 212, 213, 293
ess than or equa to (<=) cond t on, 199
fet mes, of objects, 103 105
L FO ( ast n, first out), 226
L m tReached event, 260
L neNumberOffset property, 310
L nePos t onOffset property, 310
L nkedL st<T> c ass, 219, 273
L nq c ass, 276
L stBox contro , 384
L stBox tems contro , 381
L st c ass, 240, 241
L st<T> c ass, 273
overv ew, 219 221
st type, STL/CLR, 226
L stV ew contro , 384
tera constant, 28
tera keyword, 93
L ve t es, 415
Load method, 325
LoadXm method, 325
Loca Name property, 307, 323, 326
oca scope, overv ew, 51 53
ocat on e ement, 331
LogAttr bute c ass, 462
og ca operators
over oad ng, 167 169
overv ew, 31 32
LongLength property, 212
ong ong type, 24
ong type, 24
LookupNamespace method, 308
LookupPrefix method, 318
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
Loya tyScheme c ass examp e
creat ng, 95 96
creat ng objects, 97 100
Index497

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

.NET, 266 268


n W ndows RT, 390
MEX (Metadata Exchange) addresses, 355
MFC (M crosoft Foundat on C asses), 370, 405
M crosoft ntermed ate Language (MS L), 229, 375
M crosoft ntermed ate Language (MS L) fi e, 81
M crosoft spec fic data types, 24
m xed c asses, and unmanaged code, 437 438
m xed anguage programm ng, except ons n,
192 195
mm c ass, 115
Modu e property, 468
modu us operator (%), 30
Move method, 290, 292
MoveNext method, 210
MoveToAttr bute method, 308
MoveToContentAsync method, 308
MoveToContent method, 308
MoveToE ement method, 308, 315
MoveToF rstAttr bute method, 308
MoveTo method, 291, 293
MoveToNextAttr bute method, 308, 315
MS L (M crosoft ntermed ate Language), 229, 264,
375
MS L (M crosoft ntermed ate Language) fi e, 81
MSMQ transport, 354
Mu t Byte Character Set (MBCS), 405
mu t cast de egates, 249 252
mu t d mens ona arrays
managed arrays, 211
nat ve arrays, 202 203
mu t map type, STL/CLR, 226
mu t p cat on operator (*), 30
mu t set type, STL/CLR, 226

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

W ndows namespaces, 275


Xm namespaces, 276
overv ew, 263
qu ck reference, 278
XML and
NET XML namespaces, 306
overv ew, 305 306
XML process ng c asses, 306 307
NetMsmqB nd ng, 355, 358
NetNamedP peB nd ng, 355, 358
Net namespaces, 275
NetTcpB nd ng, 355, 358
new operator, 203
NextS b ng property, 323, 326
NodeChanged event, 325
NodeChang ng event, 325
Node nserted event, 325
Node nsert ng event, 325
node st, 329
NodeRemoved event, 325
NodeRemov ng event, 325
NodeType property, 308 309, 324, 326
None node type, 309
NonSer a zedAttr bute c ass, 458
non stat c member funct ons, ca ng by us ng
de egates, 249
Norma ze method, 326
norma po nters, 246
not a number (NaN), 272
Notat on node type, 309
Not fyDe egate, 250
NOT operator (!), 31
NotPub c attr bute, 469
nu ptr keyword, 184
nu ptr va ue, 98
number bases
n ca cu ator examp e
add ng buttons for, 417 418
chang ng base, 418 421
convert ng str ng n d sp ay, 421 425
Numer cOp funct on, 247

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

operat on contracts, 356


operator over oad ng
and reference types, 172 173
ar thmet c operators, 161 162
best pract ces, 173 174
CLS comp ant operators, 166 167
decrement operators, 171 172
ncrement operators, 171 172
og ca operators
Equa s funct on, 169 170
overv ew, 167 169
overv ew, 159
restr ct ons on, 160
ru es for, 161
stat c operator over oads, 163 166
types need ng, 160
operators
ar thmet c operators, 30 31
ass gnment operators, 30
b tw se operators, 32 33
cast operator, 33 34
defined, 30
og ca operators, 31 32
precedence of, 34
re at ona operators, 31 32
ternary operator, 32 33
op Exc us veOr operator, 166
op GreaterThan operator, 167
op GreaterThanOrEqua operator, 167
op ncrement operator, 167
op nequa ty operator, 167
op LeftSh ft operator, 167
op LessThan operator, 167
op LessThanOrEqua operator, 167
op Log ca And operator, 167
op Log ca Not operator, 166
op Log ca Or operator, 167
op Modu us operator, 167
op Mu t p y operator, 167
op OnesComp ement operator, 166
op Po nterDereference operator, 166
op R ghtSh ft operator, 167
op Subtract on operator, 167
op UnaryNegat on operator, 166
op UnaryP us operator, 166
Orac eC ent data prov der, 334
Or entat on property, 384
OR operator, 31 32
OuterXm property, 324, 326
over oaded [ ] operator, 230


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

proxy, accessing WCF services using


proxy, access ng WCF serv ces us ng, 365 368
Pub c attr bute, 469
pub c c ass, 136
pub c keyword, 18
push back funct on, 225

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

Read method, 287, 299, 308


ReadNode method, 325
read on y propert es, 233 234, 239
ReadOuterXm method, 308
ReadSByte method, 299
ReadS ng e method, 299
ReadStartE ement method, 309
ReadState property, 308
ReadStr ng method, 299, 309
ReadToDescendant method, 309
ReadToEndAsync method, 287
ReadToEnd method, 287
ReadToFo ow ng method, 309
ReadToNextS b ng method, 309
ReadU nt16 method, 299
ReadU nt32 method, 299
ReadU nt64 method, 299
RedeemPo nts funct on, 97
refactor ng, 407
reference counted objects, 391
Reference Manager d a og box, 193
reference types, 20
and managed arrays, 208 209
and operator over oad ng, 172 173
ref keyword, 184
reflect on
obta n ng attr bute data us ng
access ng custom attr bute data, 470 472
access ng standard attr butes, 469
overv ew, 467 468
Type c ass, 467 469
ref new keyword, 391
Refresh method, 293
re nterpret cast<> operator, 34
re at ona operators, overv ew, 31 32
re at onsh ps, object
Loya tyScheme c ass examp e
creat ng, 95 96
creat ng objects, 97 100
mp ement ng c ass, 96 97
test ng app cat on, 100 101
overv ew, 95 96
Re ease Cand date (RC) vers on, 7
remember ng operat ons, n ca cu ator examp e, 406
Remote Method nvocat on (RM ), 352
remot ng, 264
RemoveAccount funct on, 241
RemoveA method, 325, 326
RemoveBy ndex method, 223
RemoveCh d method, 325 326


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

stack semant cs, and objects


creat ng objects w th, 111 113
overv ew, 116 118
Stack<T> c ass, 219, 273
StackTrace property, Except on c ass, 182
stack type, STL/CLR, 226
StandardSty es.xam fi e, 380, 426
Start W thout Debugg ng opt on, 47, 401
stat c cast<doub e> operator, 33
stat c cast<> operator, 33
stat c constructors, c ass w de, 92 93
stat c keyword, 90
stat c member funct ons, ca ng by us ng
de egates, 248 249
stat c operator over oads, over oad ng, 163 166
stdafx.h fi e, 107
stepp ng through app cat on, 47 51
STL/CLR brary
concepts beh nd, 225 227
overv ew, 224 225
Stop Debugg ng opt on, Debug menu, 165
Stream c ass, 274, 282, 284, 302
StreamReader c ass, 274, 282
streams, 302
StreamWr ter c ass, 274, 282, 283
Str ng c ass, 18, 44
overv ew, 29 30
Str ng^ parameter, 442
Str ngReader c ass, 274, 282
str ngs, n W ndows RT, 392 393
Str ngWr ter c ass, 274, 282
struct keyword, 146
StructLayoutAttr bute c ass, 449, 458
structured data, pass ng, 449 452
Structured Except on Hand ng (SEH), 178
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
sty es, 381
Sub keyword, 38
subst tutab ty, 123 124
subtract on operator ( ), 30
Supports method, 327
sw tch statement, 313
overv ew, 65 67
us ng fa through n, 67 68

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

System::Reflect on namespace, 470


System::Runt me:: nteropServ ces namespace, 437
System::Runt me::Ser a zat on namespace, 303
System::Serv ceMode ::AddressAccessDen ed
Except on, 361
System::Serv ceMode assemb y, 362
<system.Serv ceMode > e ement, 367
System::Str ng c ass, 209
System::SystemExcept on c ass, 179
System::TypeLoadExcept on c ass, 179
System::Va ueType c ass, 145, 171
System::Web::Ma namespace, 277
System::Web namespace, 277
System::Web::Secur ty namespace, 277
System::Web::Serv ces namespace, 277
System::Web::U ::Htm Contro s namespace, 278
System::Web::U namespace, 277
System::Xm ::L nq namespace, 306
System::Xm namespace, 306
System::Xm ::Schema namespace, 306, 316
System::Xm ::Ser a zat on namespace, 306
System::Xm ::XPath namespace, 306
System::Xm ::Xs namespace, 306

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

tiles, Start Page, calculator example


t es, Start Page, ca cu ator examp e, 412 415
ToB nary funct on, 423
Too t p contro , 384
ToStr ng funct on, 134
ToStr ng method, 291, 293, 469, 471
track ng hand es, 27
track ng reference, 114
tr ggers, 381
Tr mToS ze funct on, 222
Tr mToS ze method, 221
TrueForA method, 213
try b ock, 347
try/catch b ocks, hand ng except ons us ng, 180 182
TryGetVa ue method, 223
type cast ng, operator for, 33 34
Type c ass, obta n ng attr bute data us ng, 467 469
typedefs, overv ew, 29
TypedEventHand er, 432
type safe, 121

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

pass ng structured data, 449 452


vs. managed code
GCHand e type, 438 440
m xed c asses, 437 438
overv ew, 437
UpdateCommand, 345
User32.d , 445
user nterface (U ) framework, 275
#us ng d rect ve, 270

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 Store apps


W ndows::App cat onMode .DataTransfer
namespace, 430
W ndows::App cat onMode namespaces, 393
W ndows app cat ons
M crosoft Foundat on C asses, 370
W n32 AP , 369 370
W ndows Forms, 370 371
W ndows Presentat on Foundat on, 371
W ndows Commun cat on Foundat on (WCF), 275
W ndows::Data namespaces, 393
W ndows::Dev ces namespaces, 393
W ndows Forms, 370 371
W ndows::Foundat on::Co ect ons namespaces, 393
W ndows::Foundat on namespaces, 393
W ndows::G oba zat on namespaces, 393
W ndows::Graph cs namespaces, 393
W ndows::Management namespaces, 393
W ndows::Med a namespaces, 393
W ndowsMessageBox funct on, 448
W ndows namespaces, 275
W ndows::Network ng namespaces, 393
W ndows Presentat on Foundat on, 371
W ndows Presentat on Foundat on (WPF), 275
W ndows RT (W nRT). SeeW nRT
W ndows Runt me L brary (WRL), 390
W ndows::Secur ty namespaces, 393
W ndows::Storage namespaces, 393
W ndows Store apps
and W ndows app cat ons
M crosoft Foundat on C asses, 370
W n32 AP , 369 370
W ndows Forms, 370 371
W ndows Presentat on Foundat on, 371
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, 416 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, 428 432
test ng, 410 412
choos ng U brary, 372
creat ng, 375 379
fi e structure for, 379 380
Index507

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

Wr teE ementStr ng method, 319


Wr teEndAttr bute method, 319
Wr teEndDocument method, 319
Wr teEndE ement method, 319
Wr teEnt tyRef method, 319
Wr teFu EndE ement method, 319
Wr teL neAsync method, 283
Wr teL ne method, 283
Wr teL ne statement, 108, 111, 162
Wr te method, 283, 298
Wr teName method, 319
Wr teNode method, 319
wr te on y propert es, 233 234
Wr teProcess ng nstruct on method, 319
Wr teQua fiedName method, 319
Wr teRaw method, 319
Wr teStartAttr bute method, 319
Wr teStartDocument method, 319
Wr teStartE ement method, 319
Wr te statement, 108
Wr teState property, 318
Wr teStr ng method, 319
Wr teTo method, 325, 327
Wr teVa ue method, 319
Wr teWh tespace method, 319
Wr teXm method, 348
WRL (W ndows Runt me L brary), 390
WSDL (Web Serv ce Defin t on Language), 355
WSDL (Web Serv ce Descr pt on Language), 306
WSDua HttpB nd ng, 355, 358
WSHttpB nd ng, 355, 358, 360, 362

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

You might also like