??xml version="1.0" encoding="utf-8" standalone="yes"?>
System::String^ saying = L"Many hands make light work.";
跟踪句柄saying用于讉KStringcd象。该对象的字Wؓ宽字W,因ؓ采用了前~ “L”Q如果省?#8220;L”Q该字符串由8位的字符l成Q编译器确保将其{换成宽字W?/p>
讉K字符串内字符可以像访问数l元素一P使用索引来访问,首字W的索引?。这U方法只能用于读取字W串内字W,但不能用于修改字W串的内宏V?/p>
Console::WriteLine("The third character in the string is {0}", saying[2]);
利用Length属性,可以获取字符串内字符的数量(长度Q?/p>
Console::WriteLine("The saying has {0} charactors.", saying->Length);
利用 “+”可以q接字符Ԍ形成新的字符丌Ӏ执行下面的例子之后Qname3包含字W串 “Beth and Betty”?/p>
String^ name1 = L"Beth"; String^ name2 = L"Betty"; String^ name3 = name1+L" and "+name2;
“+”q可以用来连接字W串与数倹{bool值等非字W串变量Q在q接之前Q这些变量将自动的{换成字符丌Ӏ?/p>
String^ str = L"Value: "; String^ str1 = str + 2.5; // str1 is "Value: 2.5" String^ str2 = str + 25; // str2 is "Value: 25" String^ str3 = str + true; // str3 is "Value: True"
“+”q可以用来连接字W串与字W,但要注意Q?strong>l果字符串的形式取决于字W的cd?/strong>q是因ؓcharcd的字W被视ؓ数|wchar_t与String对象的字W具有相同的cdQCharcdQ?/p>
char ch = 'Z'; wchar_t wch = 'Z'; String^ str4 = str + ch; // str4 is "Value: 90" String^ str5 = str + wch; // str5 is "Value: Z"
Stringcd定义了Join()函数Q用于将数组中的多个字符串连接成一个字W串Q数l元素之间用分隔W隔开Q如
array<String^>^ names = {"Jill", "Ted", "Mary", "Eve", "Bill"}; String^ seperator = " and "; String^ joined = String::Join(seperator, names); // joined is "Jill and Ted and Mary and Eve and Bill"
特别注意QString对象是固定不变的Q一旦创建完毕后׃能再被修改了。这意味着所有的字符串操作都是在创徏新的字符丌Ӏ?/strong>
例子Q处理字W串
整数数l内的元素按列整齐地输出?/p>
// Ex4_17.cpp : main project file. #include "stdafx.h" using namespace System; int main(array<System::String ^> ^args) { array<int>^ values = { 2, 456, 23, -46, 34211, 456, 5609, 112098, 234, -76504, 341, 6788, -909121, 99, 10 }; String^ formatStr1 = "{0, "; String^ formatStr2 = "}"; String^ number; int maxLength = 0; for each(int value in values) { number = ""+value; if(maxLength<number->Length) maxLength = number->Length; } String^ format = formatStr1+(maxLength+1)+formatStr2; int numberPerLine = 3; for(int i=0; i<values->Length; i++) { Console::Write(format, values[i]); if((i+1)%numberPerLine == 0) Console::WriteLine(); } }
输出?/p>
2 456 23 -46 34211 456 5609 112098 234 -76504 341 6788 -909121 99 10
Trim()函数用于删除字符串头部和N的空根{不带参数调用该函数删除字W串头、尾部的全部I格q返回一新字W串?/p>
String^ str = {" Handsome is as handsome does... "};
String^ newStr = str->Trim();
也可传递给Trim()函数字符数组作ؓ参数Q字W串?strong>从头部和N开?/strong>删除数组中的字符。如果字W出现在字符串中_则不会被删除?/p>
String^ toBeTrimed = L"wool wool sheep sheep wool wool wool";
array<wchar_t>^ notWanted = {L'w', L'o', L'l', L' ' };
Console::WriteLine(toBeTrimed->Trim(notWanted));
上面的语句将输出
sheep sheep
如果在上面的语句中没有加前缀”L“Q则字符为charcdQ对应于System::SBytecd。不q编译器自动地其转换成wchar_tcdQ即System::CharcdQ?/p>
Trim()函数也支持直接输入要删除的字W列表,下面的语句将产生同样的输?/p>
Console::WriteLine(toBeTrimed->Trim(L'w', L'o', L'l', L' '));
如果仅仅惌删除头部或者尾部中的一端,可以使用TrimStart或者TrimEnd函数?/p>
如果要在字符串的一端填充空格或其它字符Q这一般用于以固定宽度靠左或靠叛_齐输出文本)Q可使用PadLeft()和PadRight()函数。如果字W串长度大于指定的长度参敎ͼ则返回字W串为长度等于原来字W串的新字符丌Ӏ?/p>
String^ value = L"3.142"; String^ leftPadded = value->PadLeft(10); // Result is " 3.142" String^ rightPadded = value->PadRight(10); // Result is "3.142 " String^ leftPadded2 = value->PadLeft(10, L'*'); // Result is "*****3.142" String^ rightPadded2= value->PadRight(10,L'#'); // Result is "3.142#####"
如果需要将字符串{换成大写或小写,可用ToUpper()或ToLower函数?/p>
String^ proverb = L"Many hands make light work." String^ upper = proverb->ToUpper(); // Result is "MANY HANDS MAKE LIGHT WORK."
如果需要在字符串中间插入一个字W串Q可使用Insert()函数Q第一个参数指定v始位|的索引Q第二个参数指定要插入的字符丌Ӏ?/p>
String^ proverb = L"Many hands light work."; String^ newProverb = proverb->Insert(5, "deck ");
l果?/p>
Many deck hands make light work.
如果要用另一个字W替换字W串中指定的字符Q或者用另一个子串替换字W串中给定的子串Q可使用Replace()函数?/p>
String^ proverb = L"Many hands make light work." Console::WriteLine(proverb->Replace(L' ', L'*'); Console::WriteLine(proverb->Replace(L"Many hands", L"Press switch");
输出?/p>
Many*hands*make*light*work. Pressing switch make light work.
如果需要测试字W串是否以给定的子串开始或l束Q可使用StartWith()或EndWith()函数。要L的子串句柄作为参C递给函数Q返回bool倹{?/p>
String^ snetence = L"Hide, the cow's outside."; if(sentence->StartWith(L"Hide")) Console::WriteLine("The sentence starts with 'Hide'.");
IndexOf()函数用于q回l定字符或子串在字符串中扑ֈ的第一个实例烦引,如果未找刎ͼ则返?1?/p>
String^ sentence = L"Hide, the cow's outside."; int ePosition = sentence->IndexOf(L'e'); // Return 3 int thePosition = sentence->IndexOf(L"the"); // Retuen 6
也可以指定IndexOf搜烦的v始烦引,q一般用于遍历整个字W串扑և所有的实例Q如下面的例子:
int index = 0; int count = 0; while((index=words->IndexOf(word, index))>=0) { index += word->Length; count++; } Console::WriteLine(L"'{0}' was found {1} times in: {2}", word, count, words);
LastIndexOf()函数cM于IndexOf()函数Q不q它用于从字W串N或指定烦引位|开始,倒着向头部搜索。注意:如果从尾部开始的索引值是words->Lenght-1?/p>
如果要搜索一个字W串数组中Q意元素出现在字符串中的位|,可以使用IndexOfAny()函数。同P它也有倒序搜烦的版本?下面的例子说明了IndexOfAny()的用法?/p>
例子Q搜索字W串中的标点W号
// Ex4_18.cpp : main project file. #include "stdafx.h" using namespace System; int main(array<System::String ^> ^args) { array<wchar_t>^ punctuation = {L'"', L'\'', L'.', L',', L':',L'!', L'?'}; String^ sentence = L"\"It's chilly in here\", the boy 's mother said coldly."; array<wchar_t>^ indicators = gcnew array<wchar_t>(sentence->Length){L' '}; int index = 0; int count = 0; while((index=sentence->IndexOfAny(punctuation, index))>=0) { indicators[index] = L'^'; ++index; ++count; } Console::WriteLine(L"There are {0} punctuation charactors in the string:", count); Console::WriteLine(L"\n{0}\n{1}", sentence, gcnew String(indicators)); return 0; } 输出?/em>
There are 6 punctuation charactors in the string: "It's chilly in here", the boy 's mother said coldly. ^ ^ ^^ ^ ^
跟踪句柄cM于本地C++指针Q但也有很大区别。跟t句柄确实存储着某个对象的地址Q但当CLR压羃堆过E中改变了该对象的地址Q则垃圾回收器自动更新句柄所包含的地址。我们不能像本地指针那样用跟t句柄来执行地址的算术运,也不允许对跟t句柄进行强制类型{换?
在CLR堆中创徏的对象必被跟踪句柄引用。所有属于引用类型的对象都存储在堆中Q因此ؓ引用q些对象所创徏的变量都必须是跟t句柄。例如,Stringcd是引用类型,因此引用String对象的变量必L跟踪句柄。值类型默认分配在堆栈上,但也可以用gcnew操作W将其存储在堆上。此外必L意,在堆上分配的变量——其中包括所有CLR引用cd——都不能在全局作用域内声明?
通过在类型名U后?#8221;^”W号Q用于声明一个该cd的句柄?/p>
声明了一个Stringcd的跟t句柄proverb?
在声明时句柄Ӟpȝ自动为其分配一个空|该句柄不引用M对象。也可显C地某个句柄置为空?
proverb = nullptr;
注意不能?来表C空倹{如果用0来初始化某个句柄Q则0自动{换ؓ被引用类型的对象Q而句柄则指向该对象?
可以在声明句柄时昄的将其初始化Q?/p>
String^ saying = L"I used to think I was indecisive but now I??¡ê¡èm not so sure.;"
该语句首先在堆上创徏一个包含等号右边字W串的String对象Q然后将该对象的地址存入saying中。注意字W串字面值的cd为const wchar_t*而非String。类String提供了这LҎ(gu)使得const wchar_t*cd的字W串可以用来创徏Stringcd的对象?
下面q条语句创徏了值类型的句柄Q?/p>
int^ value = 99;
该语句在堆上创徏一个Int32型的值类型变量,然后该变量的地址存入句柄value中。由于value是一U指针,因此不能直接参与术q算Q可使用*q算W对地址求|cM于本地C++指针那样Q?
int result = 2*(*value)+15;
׃*value表示value所指向地址存储的数|因此result的gؓ2*99+15=213。注意,当value作ؓq算式左值时Q不需?卛_对value指向的变量赋倹{?
int^ result = 0;
result = 2*(*value)+15;
首先创徏了一个指向数?的句柄result。(该语句会触发一条编译器警告Q提CZ能利?来将句柄初始化ؓI倹{)
W?条语?号右边ؓ数|而左边ؓ句柄Q编译器自动将叛_D予句柄所指向的对象,卛_其{换ؓ如下语句
*result = 2*(*value)+15;
注意Q要采用上面的语句,result句柄必须实际定义q。如果仅仅声明了resultQ则会生运行时错误
int^ result;
*result = 2*(*value)+15;
q是因ؓW二句要对地址result求|x味着result指向的对象已l存在,但实际ƈ非如此,因ؓ声明该对象时pȝ默认赋予其空?nullptr)。在q种情况下,采用下面的方法就可以正常工作?
int^ result;
result = 2*(*value)+15;
CLR数组是分配在可回收垃圑֠上的。必ȝarray<typename>指出要创建的数组Q同其它CLR堆上的对象一P需要用句柄来访问它Q例子如下:
array<int>^ data;
数组句柄data可用于存储对元素cd为int的一l数l的引用。下面的例子声明了一个句柄,q新Z个CLR数组来对此句柄初始化?/p>
array<int>^ data = gcnew array<int>(100);
和本地C++数组一PCLR数组中元素的索引g是从0开始的Q可以通过[ ]讉K数组元素。数l元素都是CLR对象Q在上面的例子中数组元素为Int32型对象,它们在算术表辑ּ中就像普通的整数cd一栗?
Length属性是数组的一个重要属性,记录着数组元素的数量?/p>
for(int i=0; i<data->Length; i++) data[i] = 2*(i+1);
属性LongLength则保存了64位的数组长度?
可以用for each循环遍历数组元素?/p>
array<int>^ value = {3, 5, 6, 8, 6}; for each(int item in value) { item = 2*item + 1; Console::WriteLine("{0, 5}", item); }
该@环输?字符宽度的字D,以右寚w的方式输出当前元素的计算l果Q输出如下:
____7___11___13___17___13
数组句柄可以被重新赋|只要保持数组元素cd和维敎ͼ{Q不变即可,在前面例子中的数l句柄data指向一个intcd的一l数l,可以重新l它赋|使其指向另外的intcd1l数l:
data = gcnew array<int>(45);
数组可以在创建时通过元素列表初始化,下例在CLR堆上创徏了一个doublecd的数l,q将引用赋值给了数l句柄:
array<double>^ sample = {3.4, 2.3, 6.8, 1.2, 5.5, 4.9, 7.4, 1.6};
如果在声明数l句柄时不进行初始化Q那么在l句柄赋值时不能采用上面的方法直接用元素列表用作叛_|而必采用显C创建的方式。即不能
array<double>^ sample;
sample = {3.4, 2.3, 6.8, 1.2, 5.5, 4.9, 7.4, 1.6}
而必采用如下方?
array<double>^ sample; sample = gcnew array<double>{3.4, 2.3, 6.8, 1.2, 5.5, 4.9, 7.4, 1.6}
对于字符串数l,注意每一个元素也是引用类型,q是因ؓ每一个元素String也是在CLR堆上创徏的,因此也要用String^来访问它?
array<String^>^ names = {"Jack", "John", "Joe", "Jessica", "Jim", "Joanna"};
可以用Arrayc静态函数Clear()Ҏ(gu)l中的连l数l元素清零?
Array::Clear(samples, 0, samples->Length);
Clear()函数的第一个参数是被清零的数组Q第二个参数是要清除地第一个元素的索引Q第三个参数清除地元素数量。因此上q语句将samples数组的所有元素都|ؓ0。如果Clear()清除的是某个跟踪句柄Q则句柄所对应的元素都被应用Clear()函数。如果元素ؓbool型,则被|ؓfalse?
Arrayc还定义了一个Sort()静态函敎ͼ可用于对数组q行排序。如果以数组句柄作ؓ参数Q则Ҏ(gu)个数l排序。如果要Ҏ(gu)l部分排序,则还需要增加元素v始烦引及数量Q如下例
//////////////////////////////////////////////////////// array<int>^ samples = {27, 3, 54, 11, 18, 2, 16}; Array::Sort(samples, 2, 3); ////////////////////////////////////////////////////////
排序后数l元素变为{27, 3, 11, 18, 54, 2, 16}
Sort函数q有很多其它版本Q下面的例子展示了如何排序两个相关的数组Q即W一个数l中的元素是W二个数l对应元素的键。对W一个数l排序后Q可对第二个数组q行相应的调_使得键与值相互对应?/p>
/////////////////////////////////////////////////////////////////////////// // Ex4_13.cpp : main project file. #include "stdafx.h" using namespace System; int main(array<System::String ^> ^args) { array<String^>^ names = { "Jill", "Ted", "Mary", "Eve", "Bill", "Al" }; array<int>^ weights = {103, 168, 128, 115, 180, 176}; Array::Sort(names, weights); for each( String^ name in names ) Console::Write(L"{0, 10}", name); Console::WriteLine(); for each(int weight in weights) Console::Write(L"{0, 10}", weight); Console::WriteLine(); return 0; } /////////////////////////////////////////////////////////////////////////////
输出为:
Al Bill Eve Jill Mary Ted
176 180 115 103 128 168
例子说明
Sort()函数?个数l排序时Q用W一个数l参数来定两个数组的顺序,以此保持2个数l元素对应关pM变?
Arrayc还提供了函数BinarySearch()以用对分法搜烦法Q对一l数l或l定范围内搜索特定元素的索引位置。用该函数要求数组必须是顺序排列的Q因此在搜烦之前必须Ҏ(gu)l进行排序?/p>
array<int>^ value = { 23, 45, 68, 94, 123, 150, 203, 299 }; int toBeFound = 127; int position = Array::BinarySearch(value, toBeFound); if(position<0) Console::WriteLine(L"{0} was not found.", toBeFound); else Console::WriteLine(L"{0} was found at index position {1}", toBeFound, position);
Array::BinarySearch()的第一个参数是被搜索数l的句柄Q第二个参数是要查找的内容,q回gؓintcd的数倹{如果返回值小?则说明未扑ֈ。如果要指定搜烦范围Q则需要传?个参敎ͼ其中W?参数为搜索v始烦引,W?参数为搜索的元素数量Q第4个是要搜索的内容?/p>
array<int>^ value = { 23, 45, 68, 94, 123, 150, 203, 299 }; int toBeFound = 127; int position = Array::BinarySearch(value, 3, 6, toBeFound);
上面的代码从W?个元素开始,一直搜索到l束位置?/pre>例子Q搜索数l?/em>/////////////////////////////////////////////////////////////////////////////////////// // Ex4_14.cpp : main project file. #include "stdafx.h" using namespace System; int main(array<System::String ^> ^args) { array<String^>^ names = { "Jill", "Ted", "Mary", "Eve", "Bill", "Al", "Ned", "Zoe", "Dan", "Jean" }; array<int>^ weights = {103, 168, 128, 115, 180, 176, 209, 98, 190, 130}; array<String^>^ toBeFound = {"Bill", "Eve", "Al", "Fred"}; int result = 0; Array::Sort(names, weights); for each( String^ name in toBeFound ) { result = Array::BinarySearch(names, name); if(result<0) Console::WriteLine(L"{0} was not found.", name); else Console::WriteLine(L"{0} weights {1} lbs.", name, weights[result]); } return 0; } ///////////////////////////////////////////////////////////////////////////////////////例子说明
当搜索不到目标时QArray::BinarySearch()函数输出的ƈ非Q意负敎ͼ而是W一个大于该目标的元素烦引值的按位补码。利用该Ҏ(gu)Q可以不打ؕ序在数l中插入新倹{如Q我们希望插?#8221;Fred”到names数组?/p>
array<String^>^ names = { "Jill", "Ted", "Mary", "Eve", "Bill", "Al", "Ned", "Zoe", "Dan", "Jean" } Array::Sort(names); String^ name = L"Fred"; int position = Array::BinarySearch(names, name); if(position<0) position = ~position;此时Qposition保存的是大于Fred的第一个元素的位置Q该数值可用于插入新倹{?/p>
array<String^>^ newNames = gcnew array<String^>(names->Length+1); for(int i=0;i<position;i++) newNames[i] = names[i]; newNames[position] = name; if(position<name->Length) for(int i=position; i<names->Length; i++) newNames[i+1] = names[i]; names = nullptr;最后一句用于删除names数组?/p>
(?多维数组
C++/CLI中可以创建多l数l,最大维?2l。与ISO/ANSI C++不同的是QC++/CLI中的多维数组q数组的数l,而是真正的多l数l,创徏整数多维数组Ҏ(gu)如下Q?/p>
array<int 2>^ value = gcnew array<int, 2>(4, 5);上面的代码创Z一个二l数l,四行五列Q共20个元素。访问的Ҏ(gu)是利用多个用逗号分隔的烦引值来讉K每一个元素,而不能用一个烦引D问一?/p>
int nrows = 4; int ncols = 5; array<int, 2>^ value = gcnew array<int, 2>(nrows, ncols); for(int i=0; i<nrows; i++) for(int j=0; j<ncols; j++) value[i, j] = (i+1)*(j+1);上面的代码利用@环给二维数组value赋倹{这里访问二l数l元素的W号与本地C++不同Q后者实际上是数l的数组Q而C++/CLI是真正的二维数组Q不能用一个烦引值来讉K二维数组Q那h没有意义的。数l的l数被称为等U,上面value数组的等Uؓ2。而本地C++数组的等U始lؓ1。当Ӟ在C++/CLI中也可以定义数组的数l,Ҏ(gu)见下?/p>
例子Q用多l数l?/p>
/////////////////////////////////////////////////////////////////////////// // Ex4_15.cpp : main project file. #include "stdafx.h" using namespace System; int main(array<System::String ^> ^args) { const int SIZE = 12; array<int, 2>^ products = gcnew array<int, 2>(SIZE, SIZE); for(int i=0; i<SIZE; i++) for(int j=0; j<SIZE; j++) products[i, j] = (i+1)*(j+1); Console::WriteLine(L"Here is the {0} times table:", SIZE); // Write horizontal divider line for(int i=0; i<=SIZE; i++) Console::Write(L"_____"); Console::WriteLine(); // Write top line of table Console::Write(L" |"); for(int i=1; i<=SIZE; i++) Console::Write("{0, 3} |", i); Console::WriteLine(); // Write horizontal divider line with verticals for(int i=0; i<=SIZE; i++) Console::Write("____|", i); Console::WriteLine(); // Write remaining lines for(int i=0; i<SIZE; i++) { Console::Write(L"{0, 3} |", i+1); for(int j=0; j<SIZE; j++) Console::Write("{0, 3} |", products[i, j]); Console::WriteLine(); } // Write horizontal divider line for(int i=0; i<=SIZE; i++) Console::Write("_____", i); Console::WriteLine(); return 0; } /////////////////////////////////////////////////////////////////////////////////////////////例子说明
上面的例子创Z一?2x12的乘法表Q输出如下:
Here is the 12 times table: _________________________________________________________________ | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | ____|____|____|____|____|____|____|____|____|____|____|____|____| 1 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 2 | 2 | 4 | 6 | 8 | 10 | 12 | 14 | 16 | 18 | 20 | 22 | 24 | 3 | 3 | 6 | 9 | 12 | 15 | 18 | 21 | 24 | 27 | 30 | 33 | 36 | 4 | 4 | 8 | 12 | 16 | 20 | 24 | 28 | 32 | 36 | 40 | 44 | 48 | 5 | 5 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 | 50 | 55 | 60 | 6 | 6 | 12 | 18 | 24 | 30 | 36 | 42 | 48 | 54 | 60 | 66 | 72 | 7 | 7 | 14 | 21 | 28 | 35 | 42 | 49 | 56 | 63 | 70 | 77 | 84 | 8 | 8 | 16 | 24 | 32 | 40 | 48 | 56 | 64 | 72 | 80 | 88 | 96 | 9 | 9 | 18 | 27 | 36 | 45 | 54 | 63 | 72 | 81 | 90 | 99 |108 | 10 | 10 | 20 | 30 | 40 | 50 | 60 | 70 | 80 | 90 |100 |110 |120 | 11 | 11 | 22 | 33 | 44 | 55 | 66 | 77 | 88 | 99 |110 |121 |132 | 12 | 12 | 24 | 36 | 48 | 60 | 72 | 84 | 96 |108 |120 |132 |144 | _________________________________________________________________其中创徏二维数组的代码如下:
const int SIZE = 12; array<int, 2>^ products = gcnew array<int, 2>(SIZE, SIZE);W一行定义了一个整型常量SIZEQ用于指定每一l数l的元素数量Q第二行代码定义了一个等U?的数l,?2x12大小Q该数组用于存储12x12的乘法表乘积。然后在嵌套循环中给数组赋|大部分代码用于格式化输出以其更加美观,q里׃再说明?/p>
(?数组的数l?/h2>
如果数组的元素是引用数组的跟t句柄,那么可以创建数l的数组。同Ӟ每一l数l的长度可以不同Q即所谓的“锯形数l?#8221;。例如,用ABCDE来表C学生的成W{Q根据等U分l存储班内学生的姓名Q则可以创徏一个包?个元素的数组Q每个元素ؓ一个姓名数l(卛_W串数组Q?/p>
array<array<String ^>^>^ grades = gcnew array<array<String^>^>(5)利用上面创徏的数l,然后可以创徏5个姓名数l了
grades[0] = gcnew array<String^>{"Louise", "Jack"}; grades[1] = gcnew array<String^>{"Bill", "Mary", "Ben", "Joan"}; grades[2] = gcnew array<String^>{"Jill", "Will", "Phil"}; grades[3] = gcnew array<String^>{"Ned", "Fred", "Ted", "Jed", "Ed"}; grades[4] = gcnew array<String^>{"Dan", "Ann"};grades[n]讉Kgrades数组的第n个元素,而各元素为指向String^cd数组的句柄,因此上面的语句用于创ZString对象句柄的数l,q将创徏数组的地址赋值给了grades数组元素。同Ӟq些字符串数l的长度是不同的?/p>
上面的语句也可以用一个初始化语句来实?/p>
array<array<String^>^>^ grades = gcnew array<array<String^>^> { gcnew array<String^>{"Louise", "Jack"}, gcnew array<String^>{"Bill", "Maray", "Ben", "Joan"}, gcnew array<String^>{"Jill", "Will", "Phil"}, gcnew array<String^>{"Ned", "Fred", "Ted", "Jed", "Ed"}, gcnew array<String^>{"Dan", "Ann"}, };元素的初值必d在花括号里?/p>
例子Q用数l的数组
//////////////////////////////////////////////////////////////////////// // Ex4_16.cpp : main project file. #include "stdafx.h" using namespace System; int main(array<System::String ^> ^args) { array<array<String^>^>^ grades = gcnew array<array<String^>^> { gcnew array<String^>{"Louise", "Jack"}, gcnew array<String^>{"Bill", "Maray", "Ben", "Joan"}, gcnew array<String^>{"Jill", "Will", "Phil"}, gcnew array<String^>{"Ned", "Fred", "Ted", "Jed", "Ed"}, gcnew array<String^>{"Dan", "Ann"} }; wchar_t gradeLetter = 'A'; for each(array<String^>^ grade in grades) { Console::WriteLine(L"Students with Grade {0}:", gradeLetter++); for each(String^ student in grade) Console::Write("{0, 12}", student); Console::WriteLine(); } return 0; } ///////////////////////////////////////////////////////////////////////////例子说明
输出?/p>
Students with Grade A: Louise Jack Students with Grade B: Bill Maray Ben Joan Students with Grade C: Jill Will Phil Students with Grade D: Ned Fred Ted Jed Ed Students with Grade E: Dan Ann
]]>
ISO/ANSI C++中的控制与@环全部适用于C++/CLI。下例展CZC++/CLI控制台程序中的控制@环:
// Ex3_15.cpp : main project file. #include "stdafx.h" using namespace System; int main(array<System::String ^> ^args) { wchar_t letter;
Console::Write(L"Enter a letter:"); letter = Console::Read();
if(letter>='A') if(letter<='Z') { Console::WriteLine(L"You entered a captial letter."); return 0; }
if(letter>='a') if(letter<='z') { Console::WriteLine(L"You entered a small letter."); return 0; }
Console::WriteLine(L"You did not enter a letter."); return 0; } |
letter被声明ؓwchar_tcdQ映ؓC++/CLI中的System::CharcdQ它h一些特D的功能Q其中包括将字符代码转换为大写和写的函敎ͼChar::ToUpperQ)和Char::ToLower()Q被转换的函C为参数被传递给它:
wchar_t uppercaseLetter = Char::ToUpper(letter); |
此外q包括检字母是否大写或写的函?IsUpper()和IsLower()Q因此上例可改ؓ
wchar_t letter; wchar_t upper; Console::Write(L"Enter a letter:"); letter = Console::Read(); upper = Char::ToUpper(letter); if(upper>='A' && upper<='Z') Console::WriteLine(L"You entered a {0} letter.", Char::IsUpper(letter) ? "Capital":"Small"); else Console::WriteLine(L"You entered a small letter."); |
例子Q下面看一个新的例子,试一试用Console::ReadKey()函数Qƈ初步了解ConsoleKeyInfocR?/em>
// Ex3_16.cpp : main project file. #include "stdafx.h" using namespace System; int main(array<System::String ^> ^args) { ConsoleKeyInfo keyPress;
Console::WriteLine(L"Press a key combination - press Escape to quit."); do{ keyPress = Console::ReadKey(true); Console::Write(L"You pressed"); if(safe_cast<int>(keyPress.Modifiers)>0) Console::Write(L" {0}", keyPress.Modifiers); Console::WriteLine(L" {0} which is the {1} character?, keyPress.Key, keyPress.KeyChar); }while(keyPress.Key != ConsoleKey::Escape); return 0; } |
该程序的输入CZ如下Q?/em>
Press a key combination – press Escape to quit.
You pressed Shift A which is the A character.
You pressed Control Q?which is the character.
You pressed Alt A which is the a character.
You pressed Escape which is the ← character.
hL键l? . .
例子说明
Console::ReadKey()函数用于试按键Qƈ结果存储在ConsoleKeyInfocd象里。该cL3个可讉K属性用于帮助确定被按下的键是哪个或哪些键。属性Key识别被按下的键是哪个Q属性KeyChar是被按键的Unicode字符码,属性Modifiers表示Shift,Alt,Ctrl键的按位l合Q它是定义在System命名I间中的枚DcdConsoleModifiers的常量,包括Shift\Alt\Control?/em>
应该注意的是Q在C++/CLI中枚丑ָ量在用作数g前必被昄的强制{换ؓ值类型(整数cdQ?/em>
从输Z可以看出Q当不只一个键被按下时Q用一条语句就可以得到所有的键。这是因为Modifiers枚Dcd是用FlagsAttribute属性定义的Q该属性表明这U枚丄型是一l唯一的位标志。这使得该枚丄型的变量可以pq与在一L标志位组成,而Write()或WriteLine()函数可以识别q输出各标志位?/em>
例子Q从例子开始:
// Ex3_17.cpp : main project file. #include "stdafx.h" using namespace System; int main(array<System::String ^> ^args) { int volwels = 0; int consonants = 0; String^ proverb = L"A nod is as good as a wink to a blind horse.";
for each(wchar_t ch in proverb) { if(Char::IsLetter(ch)) { ch = Char::ToLower(ch); switch(ch) { case 'a': case 'e': case 'i': case 'o': case 'u': ++volwels; break;
default: ++consonants; break; } } }
Console::WriteLine(proverb); Console::WriteLine(L"The proverb contains {0} volwels and {1} consonants.", volwels, consonants); return 0; } |
输出如下Q?/em>
A nod is as good as a wink to a blind horse.
The proverb contains 14 volwels and 18 consanants.
例子说明
该程序计字W串中的元音与辅韛_母的个数。下面的语句定义了要分析的字W串Q?/em>
String^ proverb = L”A nod is as good as a wink to a blinds horse”;
proverb变量为String句柄的String^cdQ句柄被用来存储CLR理的无用单元堆上的某个对象的位|。重复处理proverb所引用字符串中各个字符的for each循环形式如下Q?/em>
for each(wchar_t ch in proverb)
{
// Process the current character stored in ch …
}
׃proverb字符串中的字W都是Unicode字符Q因此用wchar_tQ映ؓCharcdQ类型的变量来存储这些字W。变量ch为@环内的局部变量?/em>
相比于ISO/ANSI C++而言QC++/CLIq行了大量的扩充Qƈ且提供了大量的附加功能。主要包括:
一、基本数据类?/font>
C++/CLI中包括了所有ISO/ASNI C++中的基本数据cdQ算术运也和本地C++完全一栗除此之外,C++/CLI中还定义?U整数类型,如表1所C:
cd |
字节 |
值域 |
long long |
8 |
?9223372036854775808?223372036854775807 |
Unsigned long long |
8 |
??8446744073709551615 |
指定long long数据cdӞ需要在整数数值后面加LL或小写字母llQ如
longlong big = 123456789LL; |
指定unsinged long longcdӞ需要在整数数值后面加ULL或小写字母ullQ如
unsigned long long huge = 123456789LL; |
在C++/CLI中,每一个ISO/ANSI C++基本cd名称都映到System命名I间中定义的值类cd。在C++/CLIE序中,ISO/ANSI C++基本cd名称都是CLI中对应值类cd的简略Ş式。表2l出了基本类型、占用内存以及对应的值类cd?/font>
?
基本cd |
字节 |
CLI值类cd |
bool |
1 |
System::Boolean |
char |
1 |
System::SByte |
singed char |
1 |
System::SByte |
unsigned char |
1 |
System::Byte |
short |
2 |
System:Int16 |
unsigned short |
2 |
System::UInt16 |
int |
4 |
System::Int32 |
unsigned int |
4 |
System::UInt32 |
long |
4 |
System::Int32 |
unsigned long |
4 |
System::UInt32 |
long long |
8 |
System::Int64 |
unsigned long long |
8 |
System::UInt64 |
float |
4 |
System::Single |
double |
8 |
System::Double |
long double |
8 |
System::Double |
wchar_t |
2 |
System::Char |
默认情况下,charcd被视为singed charQ因此其兌的值类cd为System::SByte。如果编译选项/JQ则char 默认为unsigned charQ此时关联ؓSystem::Byte。System为根命名I间名,C++/CLI的值类cd在这个空间中定义。此外SystemI间中还定义了许多其他类型,如表C字W串的Stringcd、精存储的十进制小数类型Decimal{等?
在C++/CLI中,兌的值类cd为基本类型添加了重要的附加功能。编译器在需要时Q将安排原g兌cd之间的自动{换,其中从原D{换ؓ兌cd成ؓ装箱(boxing)Q反之称为拆?unboxing)。根据上下文环境Q这些变量将表现为简单的值或者对象?
׃ISO/ANSI C++基本cd的名U是C++/CLIE序中值类cd名称的别名,所以原则上C++/CLI代码中可用Q何一U名U?
int count = 10; double value = 2.5; |
与下面的代码是等L
System::Int32 count = 10; System::Double value = 2.5; |
上面2U代码是完全合法的,但应量使用基本cd名称Q如int和doubleQ而不是System::Int32和System::Double。这是因Z面描q的q种映射关系仅适用于Visual C++ 2005及以上版本的~译器,其他版本~译器未必实现这U映关pR?
基本类型{换ؓ值类cd是C++/CLI的一个重要特征。在ISO/ANSI C++中基本类型与cȝ型完全不同,而在C++/CLI中,所有数据都以类cd的Ş式存储,包括值类型(存储在堆栈上Q和引用cdQ存储在堆上Q?U?
例子QFruit CLR控制台项?/u>
在Visual Studio 2005中创建CLR Console Application目Q输入名UEx2_12Q将生成如下文g
// Ex2_12.cpp : main project file. #include "stdafx.h" using namespace System; int main(array<System::String ^> ^args) { Console::WriteLine(L"Hello World"); return 0; } |
main函数后的参数为命令行参数。然后按如下方式改写代码
// Ex2_12.cpp : main project file. #include "stdafx.h" using namespace System; int main(array<System::String ^> ^args) { int apples, oranges; int fruit;
apples = 5; oranges = 6; fruit = apples + oranges;
Console::WriteLine(L"\nOranges are not the only fruit ...");;;;;;; Console::Write(L"- and we have "); Console::Write(fruit); Console::Write(L" fruit in all.\n"); return 0; } |
新加行用_体字显C,~译后执行得到如下输出:
Oranges are not the only fruit…
- and we have 11 fuit in all.
例子说明
与ISO/ANSI C++版本比较Q变量的cdint成为C++/CLIcdSystem::Int32。如果用System::Int32替换代码中的intQ然后重新编译运行,l果没有变化?/em>
WriteLine()函数为C++/CLI函数Q定义在System命名I间的ConsolecM。Console表示标准输入输出。Write()函数cȝ另一个输出函敎ͼ不会自动换行。下面专门讨论C++/CLI的控制台输入输出?/em>
C++/CLI中特有控制台格式化输出功能,例如可用下面的代码来输出字符串与变量混合文本?
Console::WriteLine(L"There are {0} fruit.", fruit); |
Console::WriteLine()的第一个参数是L”There are {0} fruit.”Q其中{0}为格式化占位W,表示在此处插入第二个参数的|如果有更多需要插入的参数Q则该参数对应的占位W编Ll增加:{1}、{2}、{3}…。在W一个字W串参数中,~号的顺序可以颠倒,?
Console::WriteLine(L"There are {1} packages weighting {0} pounds", packageWeight, packageCount); |
格式化占位符q可以控制显C的格式Q如{1:F2}表示W?个参数显C成?位小数的点敎ͼ冒号后的为格式规?
Console::WriteLine(L"There are {0} packages weighting {1QF2} pounds ", packageCount, packageWeight); |
输出?
There are 25 packages weighting 7.50 pounds.
一般说来,可以~写格式为{n,w:Axx}的格式规范,其中n为烦引|用于选择逗号后的W几个参敎ͼ A为单个字母,表示如何对变量格式化Qxx?个或2个数字,指定参数的精度;w为有W号整数Q表C可选的字段宽度范围Q如果w?Q则字段叛_齐,如果w?Q则左对齐。如果数值的位置数小于w指定的位|数Q则多出来的用空格填充,如果数值的位置数大于w指定的位|数Q则忽略w的限定:
Console::WriteLine(L"Packages: {0,3} Weight: {1,5QF2} pounds ", packageCount, packageWeight); |
输出为(下划U表C空格填充位Q:
Packages: _25 Weight: __7.50 pounds
可选的格式说明W如?所C?/font>
?
格式说明W?/strong> |
?/strong> ?/strong> |
C或c |
把g币量输出 |
D或d |
把整C为十q制D出。如果指定的_ֺ大于位数Q则在数值的坐标填充0 |
E或e |
按照U学技术法输出点?/font> |
F或f |
把QҎ(gu)作ؓ±####.##的定Ҏ(gu)输出 |
G或g |
以最紧凑的Ş式输出,取决于是否指定了_ֺ|如果没有则适用默认_ֺ |
N或n |
把g为定点十q制D出,必要时以3位一l用逗号分隔 |
X或x |
把整C为十六进制D出。根据X或xQ以大写或小写输出?/font> |
例子Q计地毯h(hun)|演示CLR控制台程序的格式化输?/em>
// Ex2_13.cpp : main project file. #include "stdafx.h" using namespace System; int main(array<System::String ^> ^args) { double carpetPriceSqYd = 27.95; double roomWidth = 13.5; // in feet double roomLength = 24.75; // in feet const int feetPerYard = 3; double roomWidthYard = roomWidth/feetPerYard; double roomLengthYard = roomLength/feetPerYard; double carpetPrice = roomWidthYard*roomLengthYard*carpetPriceSqYd;
Console::WriteLine(L"Room is {0:F2} yards by {1:F2} yards", roomWidthYard, roomLengthYard); Console::WriteLine(L"Room area is {0:F2} square yards", roomWidthYard*roomLengthYard); Console::WriteLine(L"Carpet price is ${0:F2}", carpetPrice); return 0; } |
例子说明Q?/em>Q略Q?/em>
.Net Framework的控制台键盘输入功能有限Q可以适用Console::ReadLine()函数把整行输入作为字W串dQ或者用Console::Read()d单个字符Q还可以适用Console::ReadKey()d按键。ReadLine()的例子如下:
String^ line = Console::ReadLine(); |
用于整行文本存入字W串中,按下Enter键时Q文本结束。变量line为String^型,表示String数据cd的引用,line为Console::ReadLine()函数d字符串的引用。Read()的例子如下:
char ch = Console::Read(); |
用于逐字W的d输入数据Qƈ其转换成对应的数字倹{ReadKey的例子如下:
ConsoleKeyInfo keyPressed = Console::ReadKey(true); |
用于d按键|q返回ConsoleKeyInfo对象Q该为对象定义在System命名I间中的值类型。参数true表示按键不在命o行上昄出来Qfalse则表C显C按键回显。按键对应的字符可用ConsoleKeyInfo对象的KeyChar得到?
Console::WriteLine(L”The key press corresponds to the character: {0}”, keyPress.KeyChar); |
按键对应的键值由ConsoleKeyInfo对象的Key得到?
管C++/CLI控制台程序中不能格式化输入,但输入一般都通过H口lg得到Q因此这仅仅是一个小~陷?
在CLR环境中safe_cast用于昄的强制类型{换。safe_cast用于一U类型{换ؓ另一U类型,在不成功时能够抛出异常,因此在C++/CLI中用safe_cast是比较好的选择。其用法和static_cast一P
double value1 = 10.5; double value2 = 15.5; int whole_number = safe_cast<int>(value1) + safe_cast<int>(value2); |
C++/CLI的枚举与ISO/ANSI C++有较大的区别。下例ؓC++/CLI中的一个枚丄型:
enum class Suit {Clubs, Diamonds, Hearts, Spades}; |
该语句定义了一个枚丄型SuitQ该cd的变量只能被赋值枚丑֮义中的|且必ȝ枚Dcd名称限定枚D常数?
Suit suit = Suit::Diamonds; |
注意class关键字跟在enum之后。说明该枚Dcd为C++/CLIQ该关键字还表明在定义中规定的常? Clubs\Diamonds\Hearts\Spades都是cd象而非ISO/ANSI C++中的基本cdQ整型)倹{实际上Q默认情况下q些都是Int32cd的对象?
׃C++/CLI枚D定义中的变量都是cd象,因此不能在函数内部定义?/font>
例子
// Ex2_14.cpp : main project file. #include "stdafx.h" using namespace System; enum class Suit {Clubs, Diamonds, Hearts, Spades}; int main(array<System::String ^> ^args) { Suit suit = Suit::Clubs; int value = safe_cast<int>(suit);
Console::WriteLine(L"Suit is {0} and the value is {1}", suit, value); suit = Suit::Diamonds; value = safe_cast<int>(suit); Console::WriteLine(L"Suit is {0} and the value is {1}", suit, value); suit = Suit::Hearts; value = safe_cast<int>(suit); Console::WriteLine(L"Suit is {0} and the value is {1}", suit, value); suit = Suit::Spades; value = safe_cast<int>(suit); Console::WriteLine(L"Suit is {0} and the value is {1}", suit, value); return 0; } |
该例子的输出?/em>
Suit is Clubs and the value is 0
Suit is Diamonds and the value is 1
Suit is Hearts and the value is 2
Suit is Spades and the value is 3
例子说明
1Q?Suit为枚丄型,不能在函数main()内部定义Q因此只能定义ؓ全局作用域内?/em>
2Q?必须用类型名USuit限定枚D帔RQ如Suit::ClubsQ否则编译器无法识别?/em>
3Q?变量suit的gؓcd象,要获取其值必LC的其转换成intcd?/em>
(一Q指定枚丑ָ量的cd
枚D中常量的cd可以是下表中M基本cdQ?
short |
int |
long |
long long |
signed char |
char |
unsigned short |
unsigned int |
unsigned long |
unsigned long long |
unsigned char |
bool |
要指定一个枚丑ָ量的cdQ可以在枚Dcd名称之后写入帔Rcd名称Q要用冒号隔开Q,如下例所C:
enum class Face:char { Ace,Two,Three,Four,Five,Six,Seven,Eight,Nine,Ten,Jack,Queen,King}; |
此枚丄型中的常量ؓCharcdQ对应的基本cd为char。其中第一个常量默认情况下对应于代码?Q后面的依次递增?
(?指定枚D帔R的?/font>
可以赋予枚Dcd定义中的一个或全部常数对应的|?
enum class Face:char { Ace=1,Two,Three,Four,Five,Six,Seven,Eight,Nine,Ten,Jack,Queen,King}; |
q得Ace获得1QTwo获得2Q其余依此类推,直到King=13。如果想让Ace获得最大|则可以如下定义:
enum class Face:Char { Ace=14,Two=2,Three,Four,Five,Six,Seven,Eight,Nine,Ten,Jack,Queen,King}; |