Chapter 9 Visual C++ 語法升級

88
1 Chapter 9 Visual C++ 語語語語

description

Chapter 9 Visual C++ 語法升級. 9.1 CLR 主控台應用程式專案. CLR = Common Language Runtime - PowerPoint PPT Presentation

Transcript of Chapter 9 Visual C++ 語法升級

Page 1: Chapter 9   Visual C++ 語法升級

1

Chapter 9 Visual C++ 語法升級

Page 2: Chapter 9   Visual C++ 語法升級

2

CLR = Common Language Runtime

The Common Language Runtime (CLR) is a core component of Microsoft's .NET initiative. It is Microsoft's implementation of the Common Language Infrastructure (CLI) standard, which defines an execution environment for program code. In the CLR, code is expressed in a form of bytecode called the Common Intermediate Language (CIL, previously known as MSIL—Microsoft Intermediate Language).

9.1 CLR 主控台應用程式專案

Page 3: Chapter 9   Visual C++ 語法升級

3

9.1 CLR 主控台應用程式專案

Developers using the CLR write code in a language such asVisual C++ or VB.NET. At compile time, a .NET compiler converts such code into CIL code. At runtime, the CLR's just-in-time compiler converts the CIL code into code native to the operating system. Alternatively, the CIL code can be compiled to native code in a separate step prior to runtime by using the Native Image Generator (NGEN). This speeds up all later runs of the software as the CIL-to-native compilation is no longer necessary.

Page 4: Chapter 9   Visual C++ 語法升級

4http://prabirchoudhury.wordpress.com/2008/12/15/common-language-runtime-clr/clr_image21/

Page 5: Chapter 9   Visual C++ 語法升級

5

CLR = Common Language Runtime

前面章節使用 Win32 主控台應用程式學習標準 ANSI C++

是屬於 unmanaged 程式,適用於其他 C++ 整合環境,如: DEV C++ 、 Turbo C++ 等

本章介紹 .NET 應用程式,如何由標準的 C++ 升級至VC++

VC++ .NET 稱為 Managed Extensions for C++

只介紹常用 VC++ 或視窗應用程式會使用的語法 學習 VC++ 語法最好途徑之一是使用 CLR 主控台應用程

式,因不需考慮使用者介面 可專注在語法改變

9.1 CLR 主控台應用程式專案

Page 6: Chapter 9   Visual C++ 語法升級

6

Step1 進入 Visual C++ 2005 的整合開發環境 (IDE)

Step2

在 VC++ 2005 IDE 執行功能表【檔案 (F)/ 新增 (N)/ 專案(P) 】 開啟「新增專案」對話方塊

依下圖步驟選取「 CLR 主控台應用程式」專案,將專案名稱設為「 FirstCLRVC 」

最後按 鈕 此專案是屬於 VC++ 2005 主控台專案,也就是 .NET 應

用程式

9.1 CLR 主控台應用程式專案

Page 7: Chapter 9   Visual C++ 語法升級

7

9.1 CLR 主控台應用程式專案

Page 8: Chapter 9   Visual C++ 語法升級

8

Step3 進入 VC++ CLR 主控台應用程式專案的編輯環境 右窗格為 VC++ 2005 的程式碼編輯窗格;左邊出現「方

案總管」視窗與 Win32 主控台應用程式有差異 在「 return 0; 」敘述上方加入「 Console::Read(); 」

敘述,透過 Console.Read() 方法等待由鍵盤輸入資料 執行此敘述時會暫停,等

待由鍵盤輸入資料,一直到按 <Enter> 鍵才結束程式

加入此行敘述的目的是為了等待並讓使用者觀看主控台應用程式的輸出訊息

9.1 CLR 主控台應用程式專案

Page 9: Chapter 9   Visual C++ 語法升級

9

9.1 CLR 主控台應用程式專案

Page 10: Chapter 9   Visual C++ 語法升級

10

【說明】

using namespace System; Console 類別主要對主控台做讀取和寫入資料使用 Console 類別,必須在程式開始撰寫「 using namespace System; 」敘述含入 System 命名空間

Console::WriteLine(L“Hello World”); 在 CLR 主控台環境下的目前游標處印出小括號內雙引號括住的字串訊息後,並將游標移到下一行;此敘述印出「 Hello World 」,並將游標移下一行

Console::Read();等待由鍵盤輸入資料。執行此敘述時,程式會暫停,等待由鍵盤輸入資料,一直到按 <Enter> 鍵才結束程式的執行。加入此敘述目的是為讓使用者觀看主控台應用程式的輸出訊息

Page 11: Chapter 9   Visual C++ 語法升級

11

Step 4 完成程式撰寫,執行功能表的【偵錯 (D)/ 開始偵錯 (S) 】

編譯並執行程式 出現黑色畫面主控台視窗,顯示本專案程式執行結果

Step 5 若想回 VC++ 環境繼續編寫程式,執行功能表的【偵錯

D)/ 停止偵錯 (E) 】

9.1 CLR 主控台應用程式專案

Page 12: Chapter 9   Visual C++ 語法升級

12

9.2 主控台專案格式化輸出入

9.2.1 Write/WriteLine 方法 Write() 和 WriteLine() 都是 System::Console 類別提供的

方法,將輸出的串流由指定輸出裝置 ( 預設為螢幕 ) 顯示出來

兩者差異在 WrtieLine() 方法是將要輸出的字串包含換行控制字元 (Carriage return) 一起輸出。當此敘述執行完時,游標移到目前輸出字串下一行的最前面

Write() 方法游標會停在所輸出字串最後一個字元的後面,不會自動移下一行最前面

Page 13: Chapter 9   Visual C++ 語法升級

13

9.2.2 Read/ReadLine 方法

Read() 和 ReadLine() 是 System::Console 類別所提供的方法,用來由指定輸入裝置 ( 預設為鍵盤 ) 把鍵入的資料讀進來形成一個輸入串流放入指定的變數

ReadLine() 方法允許接受一連串的輸入串流 ( 一行字元 ) 一直到按下 <Enter> 鍵為止

Read() 只能由指定輸入裝置輸入的串流中接受一個字元

Page 14: Chapter 9   Visual C++ 語法升級

14

Page 15: Chapter 9   Visual C++ 語法升級

15

【程式碼 】 FileName:ConsoleEx.sln

01 #include "stdafx.h"

02 using namespace System;

03

04 int main(array<System::String ^> ^args)

05 {

06 Console::Write(" 請輸入你的名字: ");

07 String^ yourName; //.NET 的 String 類別,不是標準 C++ 的string 類別

08 yourName = Console::ReadLine();

09 Console::WriteLine("Hello , {0}", yourName);

10 Console::Write(" 請輸入你的年齡: ");

11 int age;

12 // 使用 int::Parse() 方法將輸入的字串轉成整數13 age = int::Parse(Console::ReadLine());

14 Console::WriteLine("{0} 您好 ! , 您是 {1} 歲 ", yourName, age);

15 Console::Read ();

16 return 0;

17 }

Page 16: Chapter 9   Visual C++ 語法升級

16

9.2.3 Format 輸出入如何格式化 Write() 和 WriteLine() 連續輸出資料時,常無法控制上

下行的資料能對齊。 Visual C++ 提供格式化符號字元,譬如:將原來的 {0} 改為 {0:D9} ,表示將第一個資料以十進制顯示且長度設為 9 ,空白處補 0 ,便可讓上下文資料對齊

格式化的數值若有小數,且格式化字元後面未接數字,則預設小數位數佔兩位;若格式化字元後面有接數字,該數字表示小數佔用的位數:

Page 17: Chapter 9   Visual C++ 語法升級

17

Page 18: Chapter 9   Visual C++ 語法升級

18

【程式碼 】 FileName:ConsoleFormat.sln

01 #include "stdafx.h"

02 using namespace System;

03

04 int main(array<System::String ^> ^args)

05 {

06 int num1, num2;

07 double num3, num4;

08 num3 = 1234.567;

09 num4 = -1234.567;

10 Console::WriteLine

11 ("num3=1234.567 \t\t num4=-1234.567 的 C/c3 格式分別為 :");

12 Console::WriteLine("num3={0:C} \t\t num4={1:c3} ", num3, num4);

13 Console::WriteLine();

14

Page 19: Chapter 9   Visual C++ 語法升級

19

15 num1 = 123456;

16 num2 = -123456;

17 Console::WriteLine();

18 Console::WriteLine

19 ("num1=123456 \t\t num2=-123456 的 D9/d3/D 格式分別為 :");

20 Console::WriteLine

21 ("num1={0:D9} \t num2={1:d3} \t num2={2:D}", num1, num2, num2);

22

23 Console::WriteLine();

24 Console::WriteLine

25 ("num3=1234.567 \t\t num4=-1234.567 的 E/e2 格式分別為 :");

26 Console::WriteLine("num3={0:E} \t num4={1:e2}", num3, num4);

27 Console::WriteLine();

Page 20: Chapter 9   Visual C++ 語法升級

20

29 num3 = 1234.567;

30 num4 = -1234.567;

31 Console::WriteLine

32 ("num3=1234.567 \t\t num4=-1234.567 的 F1/f 格式分別為 :");

33 Console::WriteLine("num3={0:F1} \t\t num4={1:f} ", num3, num4);

34 Console::WriteLine();

35

36 num3 = 1234.567;

37 num4 = -1234.567;

38 Console::WriteLine

39 ("num3=1234.567 \t\t num4=-1234.567 的 G3 和 g 格式分別為 :");

40 Console::WriteLine("num3={0:G3} \t\t num4={1:g} ", num3, num4);

41 Console::WriteLine();

Page 21: Chapter 9   Visual C++ 語法升級

21

43 num3 = 1234.567;44 num4 = -1234.567;45 Console::WriteLine46 ("num3=1234.567 \t\t num4=-1234.567 的 G/g4 格式分別為 :");47 Console::WriteLine("num3={0:G} \t\t num4={1:g4} ", num3, num4);48 Console::WriteLine();4950 num3 = 1234.567;51 num4 = -1234.567;52 Console::WriteLine53 ("num3=1234.567 \t\t num4=-1234.567 的 N3 和 n 格式分別為

:");54 Console::WriteLine("num3={0:N3} \t num4={1:n} ", num3, num4);55 Console::WriteLine();57 num1 = 123;58 num2 = -123;59 Console::WriteLine("num1=123 \t\t num2=-123 的 X 格式分別為 :");60 Console::WriteLine("num1={0:X} \t\t num2={1:x} ", num1, num2);61 Console::Read();62 return 0;63 }

Page 22: Chapter 9   Visual C++ 語法升級

22

9.2.4 自訂數值格式輸出字串

Page 23: Chapter 9   Visual C++ 語法升級

23

Page 24: Chapter 9   Visual C++ 語法升級

24

【程式碼 】 FileName:ConsoleToString.sln01 #include "stdafx.h"02 using namespace System;0304 int main(array<System::String ^> ^args)05 { 06 int myvar1 = 801234567; // 輸出結果: (080)123-456707 Console::WriteLine("1. " + myvar1.ToString("(0##) ###-

####"));0809 int myvar2 = -12345; // 輸出結果: -1234510 Console::WriteLine("2. " + myvar2.ToString("######"));1112 int myvar3 = -12345; // 輸出結果: -01234513 Console::WriteLine("3. " + myvar3.ToString("000000"));14 double myvar4 = -2.455; // 輸出結果: -2.4615 Console::WriteLine("4. " + myvar4.ToString("#.##"));

Page 25: Chapter 9   Visual C++ 語法升級

25

17 double myvar5 = -2.4; // 輸出結果: -2.4018 Console::WriteLine("5. " + myvar5.ToString("0.00"));1920 double myvar6 = -2.455; // 輸出結果: -02.4621 Console::WriteLine("6. " + myvar6.ToString("00.00"));2223 double myvar7 = 1234567890; // 輸出結果:

1,234,567,89024 Console::WriteLine("7. " + myvar7.ToString("#,#"));2526 double myvar8 = 1234567890; // 輸出結果: 123456827 Console::WriteLine("8. " + myvar8.ToString("#,"));2829 double myvar9 = 1234567890; // 輸出結果: 123530 Console::WriteLine("9. " + myvar9.ToString("#,,"));3132 double myvar10 = 1234567890; // 輸出結果: 133 Console::WriteLine("10. " + myvar10.ToString("#,,,"));

Page 26: Chapter 9   Visual C++ 語法升級

26

35 double myvar11 = 1234567890; // 輸出結果: 1,235

36 Console::WriteLine("11. " + myvar11.ToString("#,##0,,"));

37

38 double myvar12 = 0.086; // 輸出結果: 8.6%

39 Console::WriteLine("12. " + myvar12.ToString("#0.##%"));

40

41 double myvar13 = 0.08647; // 輸出結果: 8.65%

42 Console::WriteLine("13. " + myvar13.ToString("#0.##%"));

43 double myvar14 = 16800; // 輸出結果: 1.68E+4

44 Console::WriteLine("14. " + myvar14.ToString("0.###E+0"));

45

46 double myvar15 = 16800; // 輸出結果: 1.68E+004

47 Console::WriteLine("15. " + myvar15.ToString("0.###E+000"));

48

Page 27: Chapter 9   Visual C++ 語法升級

27

49 double myvar16 = 16800; // 輸出結果: 1.68E00450 Console::WriteLine("16. " + myvar16.ToString("0.###E-

000"));5152 double myvar17 = 123456; // 輸出結果: [12-34-

56]53 Console::WriteLine("17. " + myvar17.ToString("[##-##-

##]"));5455 int myvar18 = 1234; // 輸出結果: 123456 Console::WriteLine("18. " + myvar18.ToString("##;(##)"));5758 int myvar19 = 1234; // 輸出結果: (1234)59 Console::WriteLine("19. " + myvar19.ToString("(##);##"));6061 int myvar20 = -1234; // 輸出結果: (1234)62 Console::WriteLine("20. " + myvar20.ToString("##;(##)"));63 Console::ReadLine();64 return 0;65 }

Page 28: Chapter 9   Visual C++ 語法升級

28

底下介紹標準 C++ 升級至常用視窗應用程式的 VC++ 語法 1. 在 VC++ .NET 2003 的參考類別型別是使用 __gc 關鍵字

來宣告類別,在 VC++ 2005 是使用 ref 來取代 __gc ,例如

ref Car { // 敘述區塊

};

2. 在 VC++ 若要動態配置建立 ref 參考類別型別 的物件,必須使用 gcnew 來取代 new 運算子,使用 ^ 符號來取代 * 指標運算子。寫法: ref Car{

// 敘述區塊 };

…… Car^ c = gcnew Car(); // 動態配置記憶體

9.3 Visual C++ 2005 語法升級

Page 29: Chapter 9   Visual C++ 語法升級

29

3. 標準 C++ 可將指標變數設為 0 或 null ,表示指標不指向任何記憶體位址;在 VC++則是使用 nullptr 來取代 0或 null 。寫法:

C = nullptr;

4. 標準 C++ 類別的解構式是在類別名稱之前加 ~ 符號;在 VC++ 的解構式則是使用 ! 取代 ~ 符號。寫法:

!Car(){

// 為解構式,若將指標變數設為 c = nullptr; ,此時會執行解構式

} 5. 標準 C++ 一個子類別一次可同時繼承兩個以上的父類別

;但在 VC++ 2005 一個類別一次只能繼承一個父類別

Page 30: Chapter 9   Visual C++ 語法升級

30

Page 31: Chapter 9   Visual C++ 語法升級

31

6. 在 Visual C++ 如果要覆寫父類別的方法,須在父類別及子類別的方法宣告為 virtaul ,接著在子類別欲覆寫的方法 ()之後加上 override關鍵字。寫法如下:ref Car(){public: // 方法之前加入 virtual 表示此方法可以被複寫

virtual void Move(){……} } ;ref SubCar : Car(){public: // 若要複寫父類別的方法,除將方法宣告為 virtual

//還必須在 () 之後加上 overridevirtual void Move()override{……}

} ;

Page 32: Chapter 9   Visual C++ 語法升級

32

【程式碼 】 FileName:refClass.sln01 #include "stdafx.h"0203 using namespace System;04 ref class Car{05 private:06 int m_speed ;0708 public:09 // 物件的建構式 #1 10 Car() {11 m_speed = 0;12 Console::WriteLine("初始化後速度 = {0}",

m_speed);13 }14 // 物件的建構式 #2 15 Car(int vSpeed) {16 m_speed = vSpeed;17 Console::WriteLine("初始化後速度 = {0}",

m_speed);18 }

Page 33: Chapter 9   Visual C++ 語法升級

33

19 protected:20 // 物件的解構式21 !Car() {22 Console::WriteLine("車子物件消滅了 ...");23 }24 };26 void DoSomething()27 {28 Console::WriteLine(" 進入程序,並宣告 BMW 物件 ...");29 Car^ BMW = gcnew Car(10); //建立物件30 Console::WriteLine("BMW 物件宣告完成,準備離開方法 ...");31 }33 int main(array<System::String ^> ^args)34 {35 DoSomething();36 Console::WriteLine("宣告 Benz 物件 ..");37 Car^ Benz = gcnew Car(); //建立物件38 Console::WriteLine("Benz 物件宣告完成 ..");39 Console::WriteLine(" 準備執行 Benz = nullptr");40 Benz = nullptr; //物件指標指向空值41 Console::WriteLine("Benz=nullptr 執行完成 !!");42 Console::Read();43 return 0;44 }

Page 34: Chapter 9   Visual C++ 語法升級

34

上述程式之 BMW物件是在 DoSomething 方法中宣告的區域物件,而 Benz物件則是在 main函式中宣告的。結果顯示程式似乎根本就沒有執行到物件解構式 !Car

在 .NET 程式中,解構式在物件消滅時是一定會執行的,但是無法預期它什麼時候執行,唯一能確定的是, .NET Framework 一定會在之後的某一個時間執行它 為何 .NET Framework 對解構式的執行要設計成如此?這與 .NET Framework 內部的垃圾收集 (Garbage Collection) 機制有關,為了程式執行效率, .NET Framework 中的 Garbage Collection Process 會在記憶體不足或程式結束時才會回收物件的記憶體, Benz = nullptr; 敘述只是將 Benz這個物件的參考 (reference)釋放掉,並不見得會回收Benz 原本所指的物件。所以當結束執行本範例時,如下圖主控台視窗會顯示兩行「車子物件消滅了…」的訊息,接著再關掉主控台視窗。

Page 35: Chapter 9   Visual C++ 語法升級

35

9.4.1 property 屬性的建立 第七章 使用方法 ( 成員函式 ) 的方式來設定屬性值,這種方式有個小缺點,在設定屬性時必須用呼叫方法加參數的方式

例 : 物件 -> 方法 (500); 不能直接使用指定屬性值方式 : 物件 -> 屬性 = 500 ,不很方便

以往 C++ 中是使用這種方式設定屬性值。現在 VC++ 可用 property 建立屬性,語法:

property 資料型別 屬性名稱 { // 屬性區塊 void set( 資料型別 ); // set 為設定屬性區塊 資料型別 get(); // get 為取得屬性區塊 }

9.4 Visual C++ 2005 屬性的建立

Page 36: Chapter 9   Visual C++ 語法升級

36

【程式碼 】 FileName:PropertyUsing_get_set.sln01 # include "stdafx.h"03using namespace System;04ref class Car {05private:06 int m_speed;0708public:09 // 設定 Speed 屬性10 property int Speed {11 int get() {12 return m_speed; // 傳回屬性值13 }14 void set(int value){15 if (value < 0) { // 速度不得低於 016 value = 0;17 }

Page 37: Chapter 9   Visual C++ 語法升級

37

18 if (value > 200) {// 速度不得高於 20019 value = 200;20 }21 m_speed = value; // 設定屬性值22 }23 }24};26int main (array<System::String ^> ^args)27{28 Car^ Benz = gcnew Car();29 Benz->Speed = 500; // 速度值超過 20030 Console::WriteLine(Benz->Speed);31 Console::Read();32 return 0;33}

Page 38: Chapter 9   Visual C++ 語法升級

38

方法之一是使用上述的 Speed 屬性中,在 set {…} 區段中不加入任何程式碼或只加入顯示錯誤訊息程式

可做出唯讀屬性,但在程式編譯階段, C++ 編譯器並不會對 Benz->Angle = 180; 之類的設定屬性敘述,出現任何錯誤或警告訊息

因語法並無任何錯誤,標準作法是在屬性定義中只能出現 get {…} 區段,絕不能加入 set {…} 區段

9.4.2 如何建立唯讀 (ReadOnly) 屬性

Page 39: Chapter 9   Visual C++ 語法升級

39

【程式碼 】 FileName:ReadOnlyProperty.sln01 #include "stdafx.h"03 using namespace System;04 ref class Car {05 private:06 static int m_angle = 10;07 public:08 property int Angle {09 int get() {10 return m_angle;11 }12 }13 };15 int main (array<System::String ^> ^args)16 {17 Car^ Benz = gcnew Car();18 Console::WriteLine(Benz->Angle);19 Console::Read();20 return 0;21 }

Page 40: Chapter 9   Visual C++ 語法升級

40

【程式碼 】 FileName:WriteOnlyProperty.sln01 #include "stdafx.h"03 using namespace System;04 ref class Car05 {06 private:07 static bool m_turbo = false;09 public: 10 property bool Turbo {11 void set(bool value) {12 m_turbo = value;13 }14 }15 };17 int main(array<System::String ^> ^args)18 {19 Car^ Benz = gcnew Car();20 Benz->Turbo = true;21 return 0;22 }

9.4.3 如何建立唯寫 (WriteOnly)屬性

Page 41: Chapter 9   Visual C++ 語法升級

41

9.5 Visual C++ 2005 事件的建立

沿用之前的 Car 類別,假設希望當物件的 Speed 屬性值超過 200 時,物件能夠透過事件通知我們,並將目前速度當成事件參數,以便在事件中可知目前的速度

Page 42: Chapter 9   Visual C++ 語法升級

42

【程式碼 】 FileName:Event-1.sln01 #include "stdafx.h"03 using namespace System;04 delegate void DangerEvent(int vSpeed); // 事件 delegate 型

別06 ref class Car {07 private:08 int m_speed;10 public:11 event DangerEvent^ Danger; // 宣告事件12 property int Speed { // 定義 Speed 屬性13 int get() {14 return m_speed;15 }16 void set(int value){17 if (value > 200) {18 Danger(value); // 啟動事件19 }20 m_speed = value;21 }22 }23 };

Page 43: Chapter 9   Visual C++ 語法升級

43

25void TooFast(int vSpeed) {26 Console::WriteLine27 (" 你目前的速度是 {0},超過 200 ,請減速 !!!",

vSpeed);28}2930int main (array<System::String ^> ^args)31{32 Car^ Benz = gcnew Car();3334 // 指定 Danger 事件由 TooFast 方法來處理35 Benz->Danger += gcnew DangerEvent(TooFast);36 Benz->Speed = 300;37 Console::Read();38 return 0;39 }

Page 44: Chapter 9   Visual C++ 語法升級

44

一 . 建立 delegate型別 delegate (委派 )型別它可以指向方法的參考指標,也就是

透過 delegate型別可以呼叫物件 ( 執行個體 ) 的方法,以傳回特定的資訊在 Visual C++ 中 delegate型別最常應用在事件處理上

。本例使用下面敘述定義事件 delegate型別,其名稱為DangerEvent ,事件傳入的參數為一個 int 整數型別。(參考第 4 行程式 )

delegate void DangerEvent(int vSpeed);二 . 使用 event 敘述宣告事件 接著可在類別中宣告一個事件如下: (參考第 11 行程式 )

event DangerEvent^ Danger;// 宣告事件 此事件名稱叫做 Danger ,屬於 DangerEvent

delegate型別,且有一個整數參數 vSpeed ,將事件的定義單純化

Page 45: Chapter 9   Visual C++ 語法升級

45

三 . 觸動事件 當物件發覺 Speed 屬性值超過 200 時,要怎樣才能觸動這個事件呢?只要在 Speed 屬性 set {…} 區段 ( 設定屬性值時會執行到 ) 中,直接呼叫事件即可。 本例使用下面敘述來馬上呼叫事件。 (參考第 18 行程

式 )property int Speed { // 定義 Speed 屬性

int get() {return m_speed;

} void set(int value){

if (value > 200) {Danger(value); // 啟動事件

}m_speed = value;

}}

Page 46: Chapter 9   Visual C++ 語法升級

46

四 . 定義事件 回憶一下第六章所介紹的控制項事件,當我們在 button1

按鈕上按一下時,不是會觸動 button1_Click事件嗎?我們須將所要執行的程式寫在 button1_Click事件中

在自訂的物件中也是類似;我們在程式中設計了一個全域的 TooFast 方法,用來當做事件。既然是事件,當然參數就要和 Car 類別中的 Danger事件定義一樣才可以,也就是都有一個 vSpeed 的整數參數,用來表示目前的速度。 (參考第 25~28 行程式 )

Page 47: Chapter 9   Visual C++ 語法升級

47

五 . 指定物件發生事件所要處理的方法 當 Speed 屬性設定超過 200 時,物件會呼叫 Danger事件,然我們的事件處理方法 (函式 ) 是 TooFast … ,二者何干?

類別中所執行的是 Danger事件,跟我們後來定義的TooFast 方法原本並無關係,但我們須清楚定義「呼叫Danger事件其實就是呼叫 TooFast 方法」這項重要的事,在宣告 Benz這個 Car物件後必須再使用 gcnew 來建立屬於 DangerEvent delegate型別的實體,然後將Benz物件中的 Danger事件對應到 TooFast 方法: ( 第35 行 )Benz->Danger += gcnew DangerEvent(TooFast);

Page 48: Chapter 9   Visual C++ 語法升級

48

9.6 VC++ 2005 陣列的建立

在 VC++ 2005 中 CLR 陣列為參考型別,須使用 array < 資料型別 , 陣列維度 > 宣告陣列,再配合 gcnew 來配置陣列記憶體空間

一 . 一維陣列的宣告與初值設定 寫法 1 : array<int>^ a = {1,2,3,4};

宣告整數型別 a 陣列 並給初值 a[0]=1 ; a[1]=2 ; a[2]=3 ; a[3]=4;

Page 49: Chapter 9   Visual C++ 語法升級

49

寫法 2 : 宣告整數型別 a陣列 , 共 a[0]~a[3] 四個陣列元素

: array<int>^ a = gcnew array<int>(4); 為 a[0]~a[3] 設定陣列元素初值:

a[0]=1 ; a[1]=2 ; a[2]=3 ; a[3]=4 ;

9.6 VC++ 2005 陣列的建立

Page 50: Chapter 9   Visual C++ 語法升級

50

二 . 二維陣列的宣告與初值設定 array<int, 2>^ a = gcnew array<int, 2>(2,

3); 宣告整數型別 a陣列為 2*3 的二維陣列

設定二維陣列的初值:a[0,0]=1 ; a[0,1]=2 ; a[0,2]=3 ;a[1,0]=4 ; a[1,1]=5 ; a[1,2]=6;

9.6 VC++ 2005 陣列的建立

Page 51: Chapter 9   Visual C++ 語法升級

51

三 . 物件陣列的宣告與建立 VC++ 宣告物件陣列必須先宣告物件陣列的大小,接著再

使用 gcnew 來產生每一個物件陣列元素的實體。寫法:

// 定義 Student 類別擁有 Name 成員 ref class Student {

public :

String^ Name;

}

9.6 VC++ 2005 陣列的建立

Page 52: Chapter 9   Visual C++ 語法升級

52

宣告 Student 型別的 obj 陣列,共 obj[0]~obj[2] array<Student^> ^obj = gcnew

array<Student^>(3); 使用 gcnew 為 obj[0] 陣列元素建立 Student 型

別的物件:obj[0]=gcnew Student();obj[0]->Name=“ 楊宗煒” ;

// 設定 obj[0] 物件陣列元素的 Name 成員為“楊宗煒”

obj[1] = gcnew Student();obj[1]->Name=" 林有加 ";obj[2] = gcnew Student();obj[2]->Name=" 張會妹 ";

9.6 VC++ 2005 陣列的建立

Page 53: Chapter 9   Visual C++ 語法升級

53

【程式碼 】 FileName:CLRArray.sln01 #include "stdafx.h"0203 using namespace System;04 ref class Employee{05 public :06 String^ Name; // .NET 的 String 類別07 int Salary;08 };0910 int main (array<System::String ^> ^args)11{12 int num;13 Console::Write ( " 請輸入員工的人數: ");14 num = int::Parse (Console::ReadLine());15 array<Employee^> ^aryEmployee = gcnew

array<Employee^>(num);16 Console::WriteLine ( " 請輸入 " + num + " 位員工的姓名與薪

資 ");

Page 54: Chapter 9   Visual C++ 語法升級

54

17 for (int i=0; i<aryEmployee->Length ; i++)18 { // 建立第 i 位員工19 aryEmployee[i] = gcnew Employee();20 Console::Write ( " 第 " + (i+1) + " 位員工姓名: " );21 aryEmployee[i]->Name = Console::ReadLine () ;22 Console::Write ( " 第 " +(i+1) + " 位員工薪資: ");23 aryEmployee[i]->Salary = int::Parse (Console::ReadLine ()) ;24 }26 Console::WriteLine ( "\n 印出所有員工的姓名與薪資 ");27 Console::WriteLine ( " 編號 \t姓名 \t薪資 ");28 Console::WriteLine ( "======================");29 for (int i=0; i<aryEmployee->Length; i++)30 {31 Console::WriteLine (" " + (i+1) + "\t" + aryEmployee[i]->Name

+ "\t" + 32 aryEmployee[i]->Salary);33 }35 Console::Read ();36 return 0;37 }

Page 55: Chapter 9   Visual C++ 語法升級

55

在 .NET Framework 另提供 ArrayList 類別,建立不定長度的陣列

此種陣列資料型別為 Object ,陣列元素允許存放不同型別的資料

ArrayList 類別是包含在 System::Collections 的命名空間中,程式最開頭先撰寫引用 System:: Collections 命名空間,才可使用較簡潔物件名稱建立 ArrayList 物件類別

using namespace System::Collections; 有引用 System::Collections 命名空間,才可使用下列

語法來建立 ArrayList 物件: ArrayList^ 陣列名稱 = gcnew ArrayList();

9.7 ArrayList 類別

Page 56: Chapter 9   Visual C++ 語法升級

56

9.7.1 ArrayList 類別常用屬性

Page 57: Chapter 9   Visual C++ 語法升級

57

9.7.2 ArrayList 類別常用方法

Page 58: Chapter 9   Visual C++ 語法升級

58

線性搜尋法採用逐一訪視的方式搜尋所要的資料,當資料量龐大時,就顯得毫無效率

若資料數量有 1000筆,採用本節所討論的二分搜尋法,搜尋的次數至多不會超過 10次 (210=1024) 使用二分搜尋法前應先將資料排序 在一個已排序的序列中,首先與序列中間值比較,若搜尋資料比

中間值大,則搜尋資料必在此中間值的後面,反之則在前面 二分搜尋法每次可將搜尋範圍減半,如此對於資料量龐大時,可

提高搜尋效率

< >< <

補充:二分搜尋法

Page 59: Chapter 9   Visual C++ 語法升級

59

Page 60: Chapter 9   Visual C++ 語法升級

60

【程式碼 】 FileName:ConsoleArrayList.sln01 #include "stdafx.h“03 using namespace System;04 using namespace System::Collections;05 int main(array<System::String ^> ^args)07 {08 ArrayList^ custList = gcnew ArrayList();09 String^ custName;10 int k, count;12 // 新增作業 ,一直新增到不再新增為止13 String^ goOn = "Y";14 while (goOn->ToUpper() == "Y") { // 判斷字串的 ToUpper() 可將字

串轉成大寫16 Console::Write(" 請輸入客戶名稱 : ");17 custName = Console::ReadLine();18 custList->Add(custName);19 Console::Write(" 是否繼續輸入 ? (Y/N) : ");20 goOn = Console::ReadLine();21 Console::WriteLine();22 } 23 Console::WriteLine();

Page 61: Chapter 9   Visual C++ 語法升級

61

25 // 檢查 custList 陣列中所有的陣列元素26 Console::Write("檢查輸入資料 : ");27 count = custList->Count;28 for (k = 0; k <= count - 1; k++)29 {30 Console::Write(custList[k] + " ");31 }32 Console::WriteLine();33 // 將 custList 陣列內的元素做遞增排序34 custList->Sort();35 Console::Write("遞增排序結果 : ");36 for (k = 0; k <= count - 1; k++)37 {38 Console::Write(custList[k] + " ");39 }40 Console::WriteLine();

Page 62: Chapter 9   Visual C++ 語法升級

62

42 // 將 custList 陣列內的元素做遞減排序43 custList->Reverse();

44 Console::Write("遞減排序結果 : ");

45 for (k = 0; k <= count - 1; k++)

46 {

47 Console::Write(custList[k] + " ");

48 }

49 Console::WriteLine(); // 透過此敘述將游標移到下一行50 Console::WriteLine(); // 使游標再移一行,此時才空一行52 Console::WriteLine(" 將客戶資料由遞減改回遞增排序 ,以做二分化資料蒐詢 ");

53 Console::WriteLine();

54 custList->Reverse(); // 將 custList 陣列做遞增排序56 Console::Write("遞增排序結果 : ");

Page 63: Chapter 9   Visual C++ 語法升級

63

57 for (k = 0; k <= count - 1; k++) {59 Console::Write(custList[k] + " ");60 }61 Console::WriteLine();62 Console::WriteLine();64 //查詢作業 ,若有找到是否刪除該客戶 ; 若查無此客戶是否插入65 Console::Write(" 請輸入欲查詢的客戶名稱 : ");66 custName = Console::ReadLine();67 Console::WriteLine();68 int index;69 // 使用 BinarySearch 二分化排序的資料必須先做遞增排序70 index = custList->BinarySearch(custName);71 String^ YN = "N";73 if (index >= 0) {75 Console::WriteLine(" 第 {0} 位客戶的資料是 : {1}", index + 1,

custList[index]);77 Console::WriteLine();78 Console::Write(" 是否刪除該資料 ? (Y/N) : ");79 YN = Console::ReadLine();80 if (YN->ToUpper() == "Y") {82 custList->Remove(custName);83 }84 }

Page 64: Chapter 9   Visual C++ 語法升級

64

85 else86 {87 Console::WriteLine(" 無此客戶名稱 ! ");88 Console::Write(" 是否插入該資料 ? (Y/N) : ");89 YN = Console::ReadLine();90 if (YN->ToUpper() == "Y")91 {92 custList->Insert(count, custName); //插在陣列的

最後面93 }94 }95 Console::WriteLine();97 // 顯示陣列最後結果98 Console::Write(" 顯示陣列最後結果 :");99 count = custList->Count;100 for (k = 0; k <= count - 1; k++)101 {102 Console::Write(custList[k] + " ");103 }104 Console::WriteLine();105 Console::Read();106 return 0;107 }

Page 65: Chapter 9   Visual C++ 語法升級

65

VC++ 2005 將處理字串和字元的新方法都放在System::String 基底類別內

9.8 字元與字串

Page 66: Chapter 9   Visual C++ 語法升級

66

System:: Object::Char 對 char 資料型別提供下列方法,以便對字元作各種處理:

9.8 字元與字串

Page 67: Chapter 9   Visual C++ 語法升級

67

Page 68: Chapter 9   Visual C++ 語法升級

68

Page 69: Chapter 9   Visual C++ 語法升級

69

Page 70: Chapter 9   Visual C++ 語法升級

70

Page 71: Chapter 9   Visual C++ 語法升級

71

Page 72: Chapter 9   Visual C++ 語法升級

72

9.8.2 Visual C++ 字串類別成員

Page 73: Chapter 9   Visual C++ 語法升級

73

Page 74: Chapter 9   Visual C++ 語法升級

74

Page 75: Chapter 9   Visual C++ 語法升級

75

Page 76: Chapter 9   Visual C++ 語法升級

76

Page 77: Chapter 9   Visual C++ 語法升級

77

Page 78: Chapter 9   Visual C++ 語法升級

78

Page 79: Chapter 9   Visual C++ 語法升級

79

Page 80: Chapter 9   Visual C++ 語法升級

80

9.9 DateTime 、 Math 及 Random 類別

.NET Framework 類別庫中的 DateTime 類別可用來設定日期與時間

使用 DateTime 類別中某些屬性時,須使用 gcnew 建立 DateTime 物件實體才可使用

下例中 dateTime1 是使用 DateTime 類別所建立日期時間物件實體,此日期時間物件為西元 2007 年 1 月23 日上午 4 時 5 分 6 秒 7 豪秒

DateTime^ dateTime1 = gcnew DateTime(2007,1,23,4,5,6,7);

Page 81: Chapter 9   Visual C++ 語法升級

81

Page 82: Chapter 9   Visual C++ 語法升級

82

Page 83: Chapter 9   Visual C++ 語法升級

83

9.9.2 Math 類別

Page 84: Chapter 9   Visual C++ 語法升級

84

Page 85: Chapter 9   Visual C++ 語法升級

85

Page 86: Chapter 9   Visual C++ 語法升級

86

Page 87: Chapter 9   Visual C++ 語法升級

87

Page 88: Chapter 9   Visual C++ 語法升級

88

9.9.3 Random 亂數 在 .NET Framework 類別中庫提供 Random 類別,

此類別為 System::Random 型別,用來產生亂數 使用 Random 類別中方法時,須先建立 Random 物

件實體才可使用 下例 rnd1 是使用 Random 類別所建立的亂數物件實

體 Random ^rnd1 = gcnew Random() ;

Random 類別沒有屬性,常用的方法如下表:方法名稱 說明Next 語法:

rnd1->Next() // 傳回大於等於 0 的亂數,且小於int::MaxValuernd1->Next(n) // 傳回 0 到 n的亂數值rnd1->Next(n1,n2) // 傳回 n1 到 n2-1 的亂數值

NextDouble

語法:rnd1->NextDouble() // 傳回 0 至 1.0 之間的亂數