- Visual C++.NET 2010開發(fā)實踐:基于C++/CLI
- 鄭阿奇主編
- 3401字
- 2018-12-27 13:41:28
1.2 簡單的C++/CLI程序
在本節(jié)中通過創(chuàng)建一個簡單的CLR控制臺應(yīng)用程序,來簡單了解C++/CLI的語法結(jié)構(gòu)。
1.2.1 創(chuàng)建CLR控制臺程序
在Visual Studio 2010集成開發(fā)環(huán)境中創(chuàng)建一個CLR控制臺應(yīng)用程序。該程序?qū)目刂婆_讀取用戶輸入的值,并根據(jù)該值來計算圓的面積,并輸出到控制臺上。
【例1.1】 創(chuàng)建CLR控制臺程序。
(1)啟動Visual Studio 2010集成開發(fā)環(huán)境,在菜單欄中選擇“文件”→“新建”→“項目”菜單命令,彈出如圖1.4所示的“新建項目”對話框。

圖1.4 “新建項目”對話框
(2)在對話框的左側(cè)選擇“Visual C++”節(jié)點下的“CLR”節(jié)點,并在對話框的中部選擇“CLR控制臺應(yīng)用程序”項。在“名稱”欄中輸入Ex1_1,并在“位置”欄中指定該項目保存的位置,可以單擊“瀏覽”按鈕選擇其他保存路徑。
(3)單擊“確定”按鈕后,集成開發(fā)環(huán)境會自動創(chuàng)建Ex1_1項目,并自動打開源代碼編輯窗口。此時可以在Ex1_1.cpp源文件的main函數(shù)中添加計算圓面積的代碼。代碼如下:
// Ex1_1.cpp : 主項目文件 #include "stdafx.h" using namespace System; int main(array<System::String ^> ^args) { Console::Clear(); Console::Write(L"輸入圓的半徑: "); double r = Double::Parse(Console::ReadLine()); double area = 3.14159 * r * r; Console::WriteLine(L"半徑為{0}的圓面積為: {1}", r, area); return 0; }
(4)選擇“生成”→“生成解決方案”菜單命令以編譯項目,并選擇“調(diào)試”→“開始執(zhí)行(不調(diào)試)”菜單命令以運行項目。Ex1_1項目運行的結(jié)果如圖1.5所示。

圖1.5 Ex1_1項目的運行結(jié)果
從整體上看,使用C++/CLI編寫的程序的結(jié)構(gòu)與標(biāo)準(zhǔn)C++編寫的程序的結(jié)構(gòu)相似,其中#include指令將stdafx.h頭文件包含到Ex1_1.cpp源文件中,using指令聲明了使用的命名空間,而main函數(shù)為應(yīng)用程序的入口函數(shù)。
1.2.2 命名空間
命名空間是為了防止相同名字的不同標(biāo)識符發(fā)生沖突而設(shè)計的隔離機(jī)制,同時是一個程序集內(nèi)相關(guān)類型的一個分組。例如,System命名空間定義了許多的基本數(shù)據(jù)類型,System::IO命名空間中包含了有關(guān)I/O的類型,而System::Data命名空間則定義了基本的數(shù)據(jù)庫類型等。
C++/CLI編寫的應(yīng)用程序可以使用.NET基類庫中的類型。在.NET基類庫中,最基本的命名空間是System,其中提供了大量核心的類型,并在程序中會經(jīng)常地使用。.NET常用命名空間及其說明如表1.1所示。
表1.1 .NET常用命名空間及其說明

命名空間提供了一種從邏輯上理解和組織關(guān)聯(lián)類型的方式。與標(biāo)準(zhǔn)C++相同,C++/CLI中同樣通過using指令來將特定命名空間引入到當(dāng)前程序文件中。如果需要使用.NET中不同功能的類型時,需要引入該類型所在的命名空間。例如:
using System; // 通用基類庫類型 using System::Drawing; // 圖形呈現(xiàn)類型 using System::Windows::Forms; // GUI窗口部件類型 using System::Data; // 通用以數(shù)據(jù)為中心的類型 using System::Data::SqlClient; // SQL Server數(shù)據(jù)訪問類型
當(dāng)引入某個命名空間后,就可以使用該命名空間中的所有包含的類型。例如,如果需要創(chuàng)建Bitmap類型的實例對象,那么必須引入System::Drawing命名空間。
using System; using System::Drawing; int main(array<System::String ^> ^args) { Bitmap^ bmp = gcnew Bitmap( 32, 32 ); // 創(chuàng)建一個大小為20×20像素的位圖 … return 0; }
如果未引入System::Drawing命名空間,那么當(dāng)編譯器在解析Bitmap類型時會產(chǎn)生編譯錯誤。然而,可以通過使用完全限定名來聲明一個未引入命名空間的類型。例如:
using System; int int main(array<System::String ^> ^args) { System::Drawing::Bitmap^ bmp = gcnew System::Drawing::Bitmap( 32, 32 ); … return 0; }
雖然,使用完全限定名同樣可以正確使用命名空間中的某個類型,但是使用using指令明顯可以減少按鍵的次數(shù)。
1.2.3 應(yīng)用程序入口
從前面的程序中可以看出,C++/CLI程序同樣包含main函數(shù),而該函數(shù)僅有一個形參,這就是String^類型的數(shù)組。
main函數(shù)的參數(shù)與標(biāo)準(zhǔn)C++中main函數(shù)的參數(shù)的作用相同,它們都是用于接收在命令行上執(zhí)行程序時的輸入?yún)?shù)。C++/CLI所有的數(shù)組中都包含了一個Length屬性以記錄該數(shù)組中包含的元素數(shù),因此可以遍歷整個數(shù)組來訪問args數(shù)組中的所有參數(shù)。
【例1.2】 訪問在命令行上執(zhí)行程序的參數(shù)。其中,在main函數(shù)內(nèi)通過for循環(huán)遍歷整個數(shù)組中的參數(shù),并輸出到控制臺上。代碼如下:
// Ex1_2.cpp: 主項目文件 #include "stdafx.h" using namespace System; int main(array<System::String ^> ^args) { Console::WriteLine(L"命令行參數(shù): "); for ( int i = 0; i<args->Length; i++) // 輸出所有參數(shù) Console::WriteLine(L"參數(shù){0}: {1}", i, args[i]); return 0; }
當(dāng)成功編譯并連接Ex1_2項目后,選擇“開始”→“所有程序”→“附件”→“命令提示符”菜單命令。然后在命令行上執(zhí)行Ex1_2.exe程序,并在后面輸入一些參數(shù),其執(zhí)行的結(jié)果如圖1.6所示。

圖1.6 Ex1_2項目的運行結(jié)果
1.2.4 控制臺輸入/輸出
控制臺的輸入、輸出是由System命名空間中的Console類實現(xiàn)的,該類封裝了基于控制臺應(yīng)用程序的輸入、輸出和錯誤流操作。
1. 控制臺輸出
Console類提供了幾個靜態(tài)方法用于在控制臺上輸出字符串或含有變量的混合文本。其中,該類的WriteLine方法用于在控制臺上輸出一行文本,并自動換行;而Write方法則可以輸出單個值,但不會自動換行。例如:
Console::Write(L"半徑為8的圓"); Console::WriteLine(L"面積為: {0}", 3.14*8*8 );
WriteLine方法是將該方法名后面的圓括號中的所有內(nèi)容都輸出到命令行上,然后在這些內(nèi)容的末尾添加一個換行符,并將光標(biāo)移動到下一行的起始位置。字符串前的L表示字符串中的字符將按照寬字符輸出,其中每個字符占兩個字節(jié)。
Write方法基本上和WriteLine方法相同,其區(qū)別在于該方法并不在輸出字符串的末尾自動添加換行符。因此,可以通過多次調(diào)用Write方法將多個數(shù)據(jù)輸出到同一行中。
Write和WriteLine方法都可以接受0個、1個或多個參數(shù),這些參數(shù)之間通過逗號(“,”)隔開。在這兩個方法輸出的字符串中,可以通過大括號(“{ }”)來分別引用所帶的參數(shù)。例如:
Console::WriteLine(L"半徑為{0}的圓面積為: {1}", 8, 3.14*8*8);
其中,{0}為格式化占位符,表示將在該處插入所引用的參數(shù)的值。如果需要插入更多的參數(shù),則可以增加占位符所對應(yīng)參數(shù)的編號,如{1}、{2}、{3}等,并且編號的順序可以顛倒。例如:
Console::WriteLine(L"第{1}個半徑為{2}的圓面積為: {0}", 3.14*8*8, 1, 8);
另外,還可以在格式化占位符中指定輸出的格式、對齊方式及精度等。通常,可以指定格式化占位符的格式規(guī)范為{n,w:Axx},其中n為索引值,用于選擇逗號后的第幾個參數(shù);A為單個字母的格式化說明符,表示將如何對變量格式化,其可選的值如表1.2所示。
表1.2 常用的格式說明符及說明

xx為1個或2個數(shù)字,指定輸出參數(shù)值的精度;而w為有符號整數(shù),用于表示可選的字段寬度范圍,如果w的值為正數(shù),則輸出的字段將右對齊,而如果w的值為負(fù)數(shù),則將左對齊。如果數(shù)值的位置數(shù)小于w指定的位置數(shù),則多出來的空位用空格填充;如果數(shù)值的位置數(shù)大于w指定的位置數(shù),則忽略w的限定。例如:
Console::WriteLine(L"圓的半徑為: {0, 3}, 面積為: {1, 5:F6}", 8, 3.1415926f*8*8);
【例1.3】 控制臺格式化輸出的示例。在main函數(shù)中通過調(diào)用Console類的WriteLine方法,以不同方式格式化輸出一個負(fù)整數(shù)和一個浮點數(shù)。代碼如下:
// Ex1_3.cpp: 主項目文件 #include "stdafx.h" using namespace System; int main(array<System::String ^> ^args) { // 以不同方式格式化輸出一個負(fù)整數(shù)和一個浮點數(shù) Console::WriteLine("標(biāo)準(zhǔn)數(shù)字格式字符串:"); Console::WriteLine( L"(C) 貨幣格式: {0:C}\n" + L"(D) 十進(jìn)制格式: {0:D}\n" + L"(E) 指數(shù)計數(shù)法: {1:E}\n" + "(F) 頂點格式: {1:F}\n" + "(G) 常規(guī)格式: {0:G}\n" + " (默認(rèn)格式): {0} (default = 'G')\n" + "(N) 數(shù)字格式: {0:N}\n" + "(P) 百分比格式: {1:P}\n" + "(X) 十六進(jìn)制格式: {0:X}\n", -123, -123.45f); return 0; }
Ex1_3項目運行后,將根據(jù)標(biāo)準(zhǔn)數(shù)字格式字符串來分別格式化輸出負(fù)整數(shù)-123和浮點數(shù)-123.45f。其執(zhí)行結(jié)果如圖1.7所示。

圖1.7 Ex1_3項目的運行結(jié)果
2. 控制臺輸入
.NET框架中的Console類還提供幾個方法用于從控制臺中讀取鍵盤的輸入字符。其中,該類的ReadLine方法可以將整行的輸入作為字符串讀取,而Read方法則讀取單個字符。另外,還可以通過ReadKey方法讀取按鍵的值。
ReadLine方法將整行文本存入到一個字符串中,當(dāng)按下【Enter】鍵時,則結(jié)束文本的讀取。該方法返回一個String^類型的變量,以表示一個String數(shù)據(jù)類型的引用,其中包含實際讀入的字符串。例如:
String^ line = Console::ReadLine();
由于ReadLine方法將以字符串形式返回輸入的內(nèi)容,所以如果需要獲取從控制臺輸入的整數(shù)和雙精度浮點數(shù)時,可以通過這些基本數(shù)據(jù)類型的包裝類的Parser方法將字符串解析成該類型的值。例如:
int value1=Int32::Parse( Console::ReadLine() );//將輸入轉(zhuǎn)換為int類型的值 double value2=Double::Parse( Console::ReadLine());//將輸入轉(zhuǎn)換為double類型的值
如果需要按照逐個字符的讀取方式輸入數(shù)據(jù),那么可以調(diào)用Read方法讀取輸入的字符,并將其轉(zhuǎn)換成對應(yīng)的數(shù)字值。例如:
char ch = Console::Read(); // 讀取一個字符,并返回該字符的ASCII碼 int n = Console::Read();
Console類的ReadKey方法可以用于測試按鍵,并將讀取的結(jié)果存儲在ConsoleKeyInfo類對象中。可以通過給ReadKey方法傳遞一個bool類型的參數(shù)來指定按鍵是否在命令行中回顯,值為true表示按鍵不顯示在命令行上,而值為false則表示顯示按鍵回顯。
ConsoleKeyInfo類有3個可訪問屬性用于幫助確定被按下的是哪個或哪些鍵。其中,屬性Key是ConsoleKey枚舉類型,用于指定被按下的鍵;屬性KeyChar表示按下的鍵的Unicode字符碼,該字符碼以wchar_t類型存儲;屬性Modifiers是ConsoleModifiers枚舉類型,用于表示是否是Shift、Alt或Ctrl鍵的按鍵組合。例如:
ConsoleKeyInfo keyPressed = Console::ReadKey(true); Console::WriteLine(L"控制臺按鍵: {0}", keyPressed . Key); Console::WriteLine(L"按鍵的Unicode碼: {0}", keyPressed . KeyChar); Console::WriteLine(L"Shift Alt Ctrl按鍵: {0}", keyPressed . Modifiers);
【例1.4】 控制臺輸入示例。在main函數(shù)中通過循環(huán)調(diào)用Console類的ReadKey方法,獲取用戶的按鍵信息,并且當(dāng)按【Esc】鍵時退出。代碼如下:
// Ex1_4.cpp: 主項目文件 #include "stdafx.h" using namespace System; int main(array<System::String ^> ^args) { ConsoleKeyInfo cki; Console::WriteLine(L"按下一個鍵及任意Ctrl、Alt和Shift組合鍵."); Console::WriteLine(L"(按Esc鍵退出)"); do { cki = Console::ReadKey(true); Console::Write(L"已按下了: "); Console::Write (L"{0}鍵,", cki.Key); Console::Write (L"Unicode碼: {0},", cki.KeyChar); Console::Write (L"組合鍵: {0}", cki.Modifiers); Console::WriteLine(); } while (cki.Key != ConsoleKey::Escape); return 0; }
當(dāng)Ex1_4程序運行時,每當(dāng)用戶按下一個鍵或者包含【Ctrl】、【Shift】或【Alt】鍵的組合鍵時,都將輸出該鍵的鍵值、Unicode碼及其組合鍵。Ex1_4項目的運行結(jié)果如圖1.8所示。

圖1.8 Ex1_4項目的運行結(jié)果
- Java 開發(fā)從入門到精通(第2版)
- Access 數(shù)據(jù)庫應(yīng)用教程
- Instant Typeahead.js
- Cassandra Design Patterns(Second Edition)
- Building a Recommendation Engine with Scala
- Spring實戰(zhàn)(第5版)
- Mastering Predictive Analytics with Python
- Scala程序員面試算法寶典
- Test-Driven Machine Learning
- Qt5 C++ GUI Programming Cookbook
- 創(chuàng)意UI:Photoshop玩轉(zhuǎn)APP設(shè)計
- 奔跑吧 Linux內(nèi)核
- PhoneGap 4 Mobile Application Development Cookbook
- 超好玩的Scratch 3.5少兒編程
- 數(shù)據(jù)結(jié)構(gòu):Python語言描述